Variadic functions in Go
Introduction for aspiring Gophers
Function is variadic if and only if the last parameter is of type …T (three dots before T are not there by accident):
package mainimport "fmt"func sum(numbers ...float64) (res float64) {
for _, number := range numbers {
res += number
}
return
}func main() {
fmt.Println(sum(1.1, 2.2, 3.3))
}
It allows to pass arbitrary (variable) number of arguments. They’re available inside function through elements of a slice (numbers parameter in code above).
Only the last parameter can be preceded with … (three dots) denoting variadic function.
argument vs. parameter
Most of the time these terms can be used interchangeably but arguments usually refer to actual values in function / method call and parameters are specified in function declaration:
package mainimport "fmt"func sum(a, b float64) (res float64) {
return a + b
}func main() {
fmt.Println(sum(1.1, 1.2))
}
- a and b are parameters
- res is a named result parameter
- 1.1 and 1.2 are arguments
… becomes a slice
The actual type of …T inside the function is []T:
package mainimport "fmt"func f(names ...string) {
fmt.Printf("value: %#v\n", names)
fmt.Printf("length: %d\n", len(names))
fmt.Printf("capacity: %d\n", cap(names))
fmt.Printf("type: %T\n", names)
}func main() {
f("one", "two", "three")
}
The compiled code produces:
> go install github.com/mlowicki/lab && ./bin/lab
value: []string{"one", "two", "three"}
type: []string
length: 3
capacity: 3
Type identity
Type of variadic function isn’t equal to the one which takes slice as a last parameter:
f := func(...int) {}
f = func([]int) {}
It’s detected while building:
src/github.com/mlowicki/lab/lab.go:17: cannot use func literal (type func([]int)) as type func(...int) in assignment
Let’s put dots on the other side…
Next snippet cannot be compiled successfully:
package mainimport "fmt"func f(numbers ...int) {
fmt.Println(numbers)
}func main() {
numbers := []int{1, 2, 3}
f(numbers)
}> go install github.com/mlowicki/lab && ./bin/lab
# github.com/mlowicki/lab
src/github.com/mlowicki/lab/lab.go:11: cannot use numbers (type []int) as type int in argument to f
It’s because a single argument needs to have a int type so slice of integers is obviously not allowed. There is a mechanism directly in the language to make it working:
package mainimport "fmt"func f(numbers ...int) {
fmt.Println(numbers)
}func main() {
numbers := []int{1, 2, 3}
f(numbers...)
}
The change which is easily to overlook are three dots (…) after the argument in call to function f. It passes numbers as a list of arguments. This way it’s possible to call variadic function passing slice of elements.
Variadic functions are syntactic sugar for functions taking slice as a last parameter. They can be used to design more expressive APIs and release programmer from creating temporary slices.
If you like the post and want to get updates about new ones please follow me. Help also others discover this story by clicking ❤ below.