Go by Example

Variadic Functions

A variadic function accepts a variable number of arguments via the ...T parameter - the basis of fmt.Println, append, and ergonomic APIs.

A variadic function accepts zero or more arguments for its last parameter by prefixing the type with .... Inside the function the variadic parameter is a slice. The ... spread operator passes an existing slice as separate arguments.

Declare the last parameter with ...T. The caller can pass any number of values of that type, including none. Inside the function, the parameter behaves as a []T.

package main
 
import "fmt"
 
func sum(nums ...int) int {
    total := 0
    for _, n := range nums {
        total += n
    }
    return total
}
 
func main() {
    fmt.Println(sum())           // 0
    fmt.Println(sum(1, 2, 3))   // 6
    fmt.Println(sum(1, 2, 3, 4, 5)) // 15
}

Spread an existing slice into a variadic call with s.... The function receives the slice's elements as individual arguments.

package main
 
import "fmt"
 
func sum(nums ...int) int {
    total := 0
    for _, n := range nums {
        total += n
    }
    return total
}
 
func main() {
    nums := []int{10, 20, 30}
    fmt.Println(sum(nums...)) // 60
 
    // Mix fixed and variadic parameters
    fmt.Println(sum(1, 2, 3)) // 6
}

Variadic functions can be combined with fixed parameters. Only the last parameter can be variadic.

package main
 
import "fmt"
 
func logMessage(level string, parts ...string) {
    fmt.Printf("[%s]", level)
    for _, p := range parts {
        fmt.Printf(" %s", p)
    }
    fmt.Println()
}
 
func main() {
    logMessage("INFO", "server", "started", "on", ":8080")
    // [INFO] server started on :8080
 
    logMessage("WARN") // variadic part is empty - that is fine
    // [WARN]
}

In production

Watch for accidental slice aliasing when passing a slice with s... - the function receives the same backing array. If the callee appends to the variadic parameter, it may silently clobber the caller's data when the slice still has capacity. Prefer an explicit []T parameter when the function might mutate or extend the slice. Variadic functions enable ergonomic APIs (fmt.Println, append) but they are not magic - they are syntactic sugar over a slice. Passing a large slice with s... is no more or less efficient than passing it directly.

Enjoyed this? Get more essays on software craft delivered to your inbox.

Subscribe free