I am curious about unpacking a slice of slices and sending them as arguments to a variadic function.
Let\'s say we have a function with variadic parameters:
This is covered in Spec: Passing arguments to ... parameters:
If
f
is variadic with a final parameterp
of type...T
, then withinf
the type ofp
is equivalent to type[]T
....
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.
So in short: it is a compile-time error because sliceOfSlices
(which is of type [][]interface{}
) cannot be assigned to args
(which is of type []interface{}
) (proof on Playground).
In long:
In your first example when you do unpack(slice)
, since unpack()
expects values of interface{}
, therefore slice
(which is of type []interface{}
) will be wrapped in a new interface{}
value, and it will be passed as a single argument.
When you do unpack(slice...)
, this will pass all the values of slice
as separate values to unpack()
; this is possible because type of slice
is []interface{}
, it matches the type of the variadic parameter (args ...interface{}
).
In your second example when you do unpack(sliceOfSlices)
, again, sliceOfSlices
will be wrapped in a new interface{}
value and passed as a single argument.
But when you try unpack(sliceOfSlices...)
, that would want to pass each element of sliceOfSlices
to unpack()
, but type of sliceOfSlices
(which is [][]interface{}
) does not match the type of the variadic parameter, hence the compile-time error.
The only way to pass sliceOfSlices
to unpack()
"exploded" is to create a new slice whose type must be []interface{}
, copy the elements, then you can pass it using ...
.
Example:
var sliceOfSlices2 []interface{}
for _, v := range sliceOfSlices {
sliceOfSlices2 = append(sliceOfSlices2, v)
}
unpack(sliceOfSlices2...)
Try it on the Go Playground.
Let's use the following unpack()
function to verify the number of arguments:
func unpack(args ...interface{}) {
fmt.Println(len(args))
}
Running your example (and with my new slice creation), output is:
1
3
1
2
Which proves without ...
only a single argument is passed (wrapped in interface{}
), and using ...
all elements will be passed separately.
Try this test on the Go Playground.