What benefits arise from naming a function's return parameter(s)?
func namedReturn(i int) (ret int) {
ret = i
i += 2
return
}
func anonReturn(i int) int {
ret := i
i += 2
return ret
}
There are some benefits to naming them:
It serves as documentation.
They are auto-declared and initialized to the zero values.
If you have multiple return sites, you don't need to change them all if you change the function's return values since it will just say "return".
There are also downsides, mainly that it's easy to accidentally shadow them by declaring a variable of the same name.
Effective Go has a section on named result parameters:
The return or result "parameters" of a Go function can be given names
and used as regular variables, just like the incoming parameters. When
named, they are initialized to the zero values for their types when
the function begins; if the function executes a return statement with
no arguments, the current values of the result parameters are used as
the returned values.
The names are not mandatory but they can make code shorter and
clearer: they're documentation. If we name the results of nextInt it
becomes obvious which returned int is which.
func nextInt(b []byte, pos int) (value, nextPos int) {
[...]
Another special use for a named return variable is to be captured by a deferred function literal. A trivial illustration:
package main
import (
"errors"
"fmt"
)
func main() {
fmt.Println(f())
}
var harmlessError = errors.New("you should worry!")
func f() (err error) {
defer func() {
if err == harmlessError {
err = nil
}
}()
return harmlessError
}
Output is <nil>. In more practical scenarios, the deferred function may handle panics, and may modify other return values besides an error result. The magic in common though, is that the deferred literal has a chance to modify the return values of f after f is terminated, either normally or by panic.
It's useful in at least two cases:
Whenever you have to declare variables that you're going to return. E.g.
func someFunc() (int, error) {
var r int
var e error
ok := someOtherFunc(&r) // contrived, I admit
if !ok {
return r, someError()
}
return r, nil
}
vs.
func someFunc() (r int, e error) {
ok := someOtherFunc(&r)
if !ok {
e = someError()
}
return
}
This gets more important as the number of execution paths through the function increases.
When you're documenting return values and want to refer to them by name. godoc considers the return variables part of a function's signature.
For example, named return parameters are accessible by, well, name.
func foo() (a, b, c T) {
// ...
if qux {
b = bar()
}
// ...
return
}
This is not easy to replicate w/o named return parameters. One would have to introduce local variables of essentially the same functionality as named return parameters:
func foo() (T, T, T) {
var a, b, c T
// ...
if qux {
b = bar()
}
// ...
return a, b, c
}
So it's easier to allow that directly.
Additionally, they are accessible also in the other direction:
func foo() (a, b, c T) {
// ...
if a > c {
b = bar()
}
// ...
return
}
Etc.
Related
What I have many times in different versions in my code:
func f() (bool, bool) {
value, successFulOperation := someStuff()
return value, successFulOperation
}
// somewhere else
value, successfulOperation := f()
if value && successfulOperation {
// do stuff
}
// do stuff should only be executed if value is true AND the operation that retrieved value succeeded without an error. In other words: I don't care about value or successfulOperation. I only care about value && successfulOperation.
A solution I want to avoid (seems verbose):
value, successfulOperation := f()
actualValue := value && successfulOperation
if actualValue {...}
Above code is really simplified. In reality the if conditions will be nested and more complicated.
What I want:
A wrapper for f that combines both values into one. How do I do that? The solution should work for any function taking any parameters and returning two bools.
The following does not work:
type doubleBoolFunc func(...interface{}) (bool, bool)
func and(fn doubleBoolFunc, params ...interface{}) bool {
b1, b2 := fn(params...)
return b1 && b2
}
actualValue := and(f())
You can't write a wrapper function to turn the two bools into one until generics are in the language in go 1.181. Or at least you can, using reflect, but it's a mess.
But you can write this with go 1.17:
func both(x, y bool) bool {
return x && y
}
func f() (bool, bool) {
return true, false
}
func main() {
r := both(f())
fmt.Println(r)
}
But more practical (in my opinion) is to eschew this complication, and use a 1-line if. Not everything needs to be a function or abstracted away:
if a, b := f(); a && b {
...
}
[1] Even when generics are introduced in go 1.18, I don't think there'll be a way to specific a generic type that represents a function with arbitrary arguments that returns two bools.
func and(a, b bool) bool {
return a && b
}
then if f return 2 bool
value := and(f())
will work
To fix the code at the end of your question, don't invoke the function f(), simply reference the function name f and then list its args:
// actualValue := and(f(args...))
actualValue := and(f, args...)
https://go.dev/play/p/KAT2L58ZQy3
I have the following Golang code:
rows, err := common.GetAll(c, req, params, timer)
return common.GenericRowMarshal(200, rows, err)
I want to figure out if it's possible to do:
return common.GenericRowMarshal(200, common.GetAll(c, req, params, timer)...)
but this doesn't compile :(
It says "not enough arguments to call..."
Anyone know if this is possible somehow?
No, each time a statement executes, the function value and parameters to the call are evaluated as usual, see doc:
As a special case, if the return values of a function or method g are equal in number and individually assignable to the parameters of another function or method f, then the call f(g(parameters_of_g)) will invoke f after binding the return values of g to the parameters of f in order. The call of f must contain no parameters other than the call of g, and g must have at least one return value. If f has a final ... parameter, it is assigned the return values of g that remain after assignment of regular parameters.
func Split(s string, pos int) (string, string) {
return s[0:pos], s[pos:]
}
func Join(s, t string) string {
return s + t
}
if Join(Split(value, len(value)/2)) != value {
log.Panic("test fails")
}
If f has a final ... parameter, it is assigned the return values of g that remain after assignment of regular parameters.
For example, the following code works:
package main
import "fmt"
func main() {
f(200, g())
}
func f(i int, slice ...interface{}) {
fmt.Println(i, slice) // 200 [[1 <nil>]]
}
func g() []interface{} {
return []interface{}{1, nil}
}
I've tried this too, thinking it might work. Currently (Go 1.13) you can only do this if the inner func returns exactly the parameters that the outer function expects.
I have a function that solves the problem of Go not allowing for the setting of default values in method declarations. I want to make it just a little bit better by allowing for a variable number of return variables. I understand that I can allow for an array of interfaces as a return type and then create an interface array with all the variables to return, like this:
func SetParams(params []interface{}, args ...interface{}) (...[]interface{}) {
var values []interface{}
for i := range params {
var value interface{}
paramType := reflect.TypeOf(params[i])
if len(args) < (i + 1) {
value = params[i]
} else {
argType := reflect.TypeOf(args[i])
if paramType != argType {
value = params[i]
}
value = args[i]
}
values = append(values, value)
}
return values
}
This is an example of a method you want to define default values for. You build it as a variadic function (allowing a variable number of parameters) and then define the default values of the specific params you are looking for inside the function instead of in the declaration line.
func DoSomething(args ...interface{}) {
//setup default values
str := "default string 1"
num := 1
str2 := "default string 2"
//this is fine
values := SetParams([]interface{str, num, str2}, args)
str = values[0].(string)
num = values[1].(int)
str = values[2].(string)
//I'd rather support this
str, num, str2 = SetParams(params, args)
}
I understand that
[]interface{str, num, str2}
in the above example is not syntactically correct. I did it that way to simplify my post. But, it represents another function that builds the array of interfaces.
I would like to support this:
str, num, str2 = SetParams(params, args)
instead of having to do this:
values := SetParams([]interface{str, num, str2}, args)
str = values[0].(string)
num = values[1].(int)
str = values[2].(string)
Any advice? Help?
Please don't write horrible (and ineffective due to reflect) code to solve nonexistent problem.
As was indicated in comments, turning a language into
one of your previous languages is indeed compelling
after a switch, but this is counterproductive.
Instead, it's better to work with the idioms and approaches
and best practices the language provides --
even if you don't like them (yet, maybe).
For this particular case you can roll like this:
Make the function which wants to accept
a list of parameters with default values
accept a single value of a custom struct type.
For a start, any variable of such type, when allocated,
has all its fields initialized with the so-called "zero values"
appropriate to their respective types.
If that's enough, you can stop there: you will be able
to pass values of your struct type to your functions
by producing them via literals right at the call site --
initializing only the fields you need.
Otherwise have pre-/post- processing code which
would provide your own "zero values" for the fields
you need.
Update on 2016-08-29:
Using a struct type to simulate optional parameters
using its fields being assigned default values which happen
to be Go's native zero values for their respective data types:
package main
import (
"fmt"
)
type params struct {
foo string
bar int
baz float32
}
func myfun(params params) {
fmt.Printf("%#v\n", params)
}
func main() {
myfun(params{})
myfun(params{bar: 42})
myfun(params{foo: "xyzzy", baz: 0.3e-2})
}
outputs:
main.params{foo:"", bar:0, baz:0}
main.params{foo:"", bar:42, baz:0}
main.params{foo:"xyzzy", bar:0, baz:0.003}
As you can see, Go initializes the fields of our params type
with the zero values appropriate to their respective types
unless we specify our own values when we define our literals.
Playground link.
Providing default values which are not Go-native zero values for
the fields of our custom type can be done by either pre-
or post-processing the user-submitted value of a compound type.
Post-processing:
package main
import (
"fmt"
)
type params struct {
foo string
bar int
baz float32
}
func (pp *params) setDefaults() {
if pp.foo == "" {
pp.foo = "ahem"
}
if pp.bar == 0 {
pp.bar = -3
}
if pp.baz == 0 { // Can't really do this to FP numbers; for demonstration purposes only
pp.baz = 0.5
}
}
func myfun(params params) {
params.setDefaults()
fmt.Printf("%#v\n", params)
}
func main() {
myfun(params{})
myfun(params{bar: 42})
myfun(params{foo: "xyzzy", baz: 0.3e-2})
}
outputs:
main.params{foo:"ahem", bar:-3, baz:0.5}
main.params{foo:"ahem", bar:42, baz:0.5}
main.params{foo:"xyzzy", bar:-3, baz:0.003}
Playground link.
Pre-processing amounts to creating a "constructor" function
which would return a value of the required type pre-filled
with the default values your choice for its fields—something
like this:
func newParams() params {
return params{
foo: "ahem",
bar: -3,
baz: 0.5,
}
}
so that the callers of your function could call newParams(),
tweak its fields if they need and then pass the resulting value
to your function:
myfunc(newParams())
ps := newParams()
ps.foo = "xyzzy"
myfunc(ps)
This approach is maybe a bit more robust than post-processing but
it precludes using of literals to construct the values to pass to
your function right at the call site which is less "neat".
Recently I was playing with anonymous functions in Go and implemented an example which accepts and returns undefined parameters:
func functions() (funcArray []func(args ... interface{}) (interface{}, error)) {
type ret struct{
first int
second string
third bool
}
f1 := func(args ... interface{}) (interface{}, error){
a := args[0].(int)
b := args[1].(int)
return (a < b), nil
}
funcArray = append(funcArray , f1)
f2 := func(args ... interface{}) (interface{}, error){
return (args[0].(string) + args[1].(string)), nil
}
funcArray = append(funcArray , f2)
f3 := func(args ... interface{}) (interface{}, error){
return []int{1,2,3}, nil
}
funcArray = append(funcArray , f3)
f4 := func(args ... interface{}) (interface{}, error){
return ret{first: 1, second: "2", third: true} , nil
}
funcArray = append(funcArray , f4)
return funcArray
}
func main() {
myFirst_Function := functions()[0]
mySecond_Function := functions()[1]
myThird_Function := functions()[2]
myFourth_Function := functions()[3]
fmt.Println(myFirst_Function(1,2))
fmt.Println(mySecond_Function("1","2"))
fmt.Println(myThird_Function())
fmt.Println(myFourth_Function ())
}
I hope it helps you.
https://play.golang.org/p/d6dSYLwbUB9
I'm reading 'CreateSpace An Introduction to Programming in Go 2012'
and on page 86 I found this evil magic
func makeEvenGenerator() func() uint {
i := uint(0)
return func() (ret uint) {
ret = i
i += 2
return
}
}
// here's how it's called
nextEven := makeEvenGenerator()
fmt.Println(nextEven())
fmt.Println(nextEven())
fmt.Println(nextEven())
1) Why is i not resetting ?
2) is nextEven() returning and uint or is Println so smart that it can work with everything ?
For the sake of clarity, I'll assign names to both functions:
func makeEvenGenerator() func() uint { // call this "the factory"
i := uint(0)
return func() (ret uint) { // call this "the closure"
ret = i
i += 2
return
}
}
The factory returns the closure – functions are first class citizens in Go i.e. they can be right-hand expressions, for example:
f := func() { fmt.Println("f was called"); }
f() // prints "f was called"
In your code, the closure wraps over the context of the factory, this is called lexical scoping. This is why the variable i is available inside the closure, not as a copy but as a reference to i itself.
The closure uses a named return value called ret. What this means is that inside the closure you'll have implicitly declared ret and at the point of return, whatever value ret has will be returned.
This line:
ret = i
will assign the current value of i to ret. It will not change i. However, this line:
i += 2
will change the value of i for the next time the closure is called.
Here you'll find a little closure example I wrote together for you. It's not extremely useful but illustrates the scope, purpose and use of closures pretty well in my opinion:
package main
import "fmt"
func makeIterator(s []string) func() func() string {
i := 0
return func() func() string {
if i == len(s) {
return nil
}
j := i
i++
return func() string {
return s[j]
}
}
}
func main() {
i := makeIterator([]string{"hello", "world", "this", "is", "dog"})
for c := i(); c != nil; c = i() {
fmt.Println(c())
}
}
1) Why is i not resetting ?
Closures in Go capture variables by reference. That means the inner function holds a reference to the i variable in the outer scope, and each call of it accesses this same variable.
2) is nextEven() returning and uint or is Println so smart that it can
work with everything ?
fmt.Println() (along with fmt.Print(), fmt.Fprint(), etc.) can work most types. It prints its arguments in the "default format". It is the same thing that is printed using fmt.Printf() using the %v verb.
The variable in closure is free from neither code segment nor context.
in go tutorial following code is often seen:
a := foo()
b, c := foo()
or actually what I see is:
m["Answer"] = 48
a := m["Answer"]
v, ok := m["Answer"]
how many foo() is defined?
Is it two, one with one return type, another with two return type?
Or just one foo() with two return type defined, and somehow magically when only need one return value (a := foo()), another return value is omitted?
I tried
package main
func main() {
a := foo()
a = 1
}
func foo() (x, y int) {
x = 1
y = 2
return
}
func foo() (y int) {
y = 2
return
}
But I got error message foo redeclared in this block
While some built in operations support both single and multiple return value modes (like reading from a map, type assertions, or using the range keyword in loops), this feature is not available to user defined functions.
If you want two versions of a function with different return values, you will need to give them different names.
The Effective Go tutorial has some good information on this.
Basically, a function defines how many values it returns with it's return statement, and it's function signature.
To ignore one or more of the returned values you should use the Blank Identifier, _(Underscore).
For example:
package main
import "fmt"
func singleReturn() string {
return "String returned"
}
func multiReturn() (string, int) {
return "String and integer returned", 1
}
func main() {
s := singleReturn()
fmt.Println(s)
s, i := multiReturn()
fmt.Println(s, i)
}
Playground
The v, ok := m["answer"] example you've given is an example of the "comma, ok" idiom (Also described in the Effective Go link above). The linked documentation uses type assertions as an example of it's use:
To extract the string we know is in the value, we could write:
str := value.(string)
But if it turns out that the value does not contain a string, the program will crash with a run-time error. To guard against that, use the "comma, ok" idiom to test, safely, whether the value is a string:
str, ok := value.(string)
if ok {
fmt.Printf("string value is: %q\n", str)
} else {
fmt.Printf("value is not a string\n")
}
If the type assertion fails, str will still exist and be of type string, but it will have the zero value, an empty string.