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 main import "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 main import "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 main import "fmt" func f(names ...string) {

fmt.Printf("value: %#v

", names)

fmt.Printf("length: %d

", len(names))

fmt.Printf("capacity: %d

", cap(names))

fmt.Printf("type: %T

", 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 main import "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 main import "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.