package main
import "fmt"
func multipleRets() (int, int, int, int) {
return 11, 22, 33, 44
}
func main() {
// Q1
fmt.Println(multipleRets()) // This is fine.
fmt.Println(1, multipleRets()) // But this one errors.
// Q2
s1 := append([]int{}, []int{11, 22, 33, 44}...) // This is fine.
s2 := append([]int{}, multipleRets()) // But this one errors.
// Q3
lit1 := []int{11, 22, 33, 44} // This is fine.
lit2 := []int{multipleRets()} // But this one errors.
// Q4
fmt.Println(1, []int{11, 22, 33, 44}) // This is fine.
fmt.Println(1, []int{11, 22, 33, 44}...) // But this one errors.
}
There are 4 errors in a source code above, all of which complaining that multiple elements cannot be put in a function/literal.
But having the other examples in my mind, I can't really find a reason for those errors to be considered error.
Shouldn't they be fine? What does it mean when Go gives an error like that saying "multiple-value in single-value context"?
And the way those three pernicious dots work, how does that make sense? What exactly does ...
do?
This is why syntactic sugar is avoided by the Go designers; it leads to confusion when you expect more sugar than there is. You're seeing two types of syntactic sugar in Go here; exploding a slice to pass to a variadic function, and passing multiple return values to a function.
Exploding a slice to a variadic function is documented here: https://golang.org/ref/spec#Passing_arguments_to_..._parameters and the key detail is:
If the final argument is assignable to a slice type []T, it may be passed unchanged as the value for a ...T parameter if the argument is followed by .... In this case no new slice is created.
fmt.Println
is a function with a single, variadic parameter. That means you can either pass it individual items, or a single item which is a declared slice with the ...
explosion operator appended, in which case that slice will be passed unchanged. It can't be a slice literal, and it can't follow other parameters, in order to utilize this helper.
The other is documented here: https://golang.org/ref/spec#Calls specifically:
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.
Again, because fmt.Println
has a single, variadic parameter, you can't mix and match passing specific values with using the above syntactic sugar for passing a multi-value return straight through to the parameters of another function.
As Peter notes, "And Q3 is a slice literal, which doesn't support variadic "parameters" at all (because the values are not parameters)." The syntactic sugar above for passing multiple returns to a function doesn't apply to a slice literal simply because it is not a function at all.