You may recall that when we started the section on function calls, we were told about a “special case”… well here it is!
Calls
…
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 methodf
, then the callf(g(parameters_of_g))
will invokef
after binding the return values ofg
to the parameters off
in order. The call off
must contain no parameters other than the call ofg
, andg
must have at least one return value. Iff
has a final...
parameter, it is assigned the return values ofg
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") }
Alright, so let’s illustrate this with examples, just in case it’s not completely clear. I’ll start with two examples of this exception in action, then I’ll talk about when it doesn’t work.
func g() (int, string) {
return 13, "carrots"
}
func f(count int, item string) {
fmt.Printf("Will buy %d %s\n", count, item)
}
f(g()) // Outputs "Will buy 13 carrots"
It can also work with a variadic f
:
func f(count int, items ...string) {
switch len(items) {
case 0:
fmt.Printf("Will buy %d of nothing\n", count)
case 1:
fmt.Printf("Will buy %d %s\n", count, items[0])
default:
fmt.Printf("Will buy %d of each %s\n", count, strings.Join(items, ", "))
}
}
f(g()) // Still works as before, and outputs: "Will by 13 carrots"
func h() (int, string, string, string) {
return 8, "apples", "pears", "oranges"
}
func i() int {
return 9854
}
f(h()) // Outputs: Will buy 8 of each apples, pears, oranges
f(i()) // Outputs: Will buy 9854 of nothing
So that’s pretty much it for where this exception works. Let’s look at some examples where it doesn’t.
func j() (uint, string) {
return 12, "eggs"
}
f(j()) // cannot use j() (value of type uint) as int value in argument to f
This one is probably obvious: It fails because the return types of j
are not individually assignable to the paramaters of f
. Specifically, the first return value of type uint
is not assignable to f
’s first parameter of type int
.
f(g(), "onions") // multiple-value g() (value of type (int, string)) in single-value context
This illustrates the rule “the call of f
must contain no parameters other than the call of g
”. By adding another argument ("onions"
), we’ve told the compiler that we expect g
to return a single value, thus explaining the particular error we receive. If we really want this to work, we can do it in two steps:
count, item := g()
f(count, item, "onions")
Quotes from The Go Programming Language Specification Version of August 2, 2023