Skip to main content
Sometimes you don’t know how many arguments you’ll receive. Variadic functions solve this problem elegantly, just like fmt.Println which can accept any number of arguments.

The ... Syntax

Using ...type allows a function to accept an unlimited number of arguments of that type. Inside the function, these arguments arrive as a slice.
func sum(numbers ...int) int {
	total := 0
	for _, num := range numbers {
		total += num
	}
	return total
}
The ...int parameter means “zero or more int values”. Inside the function, numbers is just a []int slice.

Calling Variadic Functions

You can call a variadic function with any number of arguments:
result := sum(1, 2, 3, 4, 5)
println("Sum:", result)  // Output: Sum: 15

// You can also call it with no arguments
result2 := sum()
println("Sum:", result2)  // Output: Sum: 0

// Or just one argument
result3 := sum(42)
println("Sum:", result3)  // Output: Sum: 42

How It Works

The variadic parameter is treated as a slice within the function:
Since variadic parameters are slices, you can use all slice operations: len(), range, indexing, etc.

Variadic with interface{}

You can create variadic functions that accept any type using the empty interface:
func lo(numbers ...interface{}) {
	for _, num := range numbers {
		println(num)
	}
}
This allows you to pass mixed types:
lo(1, "hello", 3.14, true)
// Output:
// 1
// hello
// 3.14
// true
interface{} means “any type”. This is how fmt.Println can accept different types. In modern Go (1.18+), you might use generics instead.

Passing a Slice to Variadic Functions

If you already have a slice, you can “unpack” it using the ... operator:
numbers := []int{1, 2, 3, 4, 5}
result := sum(numbers...)  // The ... unpacks the slice
println("Sum:", result)     // Output: Sum: 15
Don’t confuse the two uses of ...:
  • In function definition: func sum(numbers ...int) - receives multiple arguments
  • In function call: sum(slice...) - unpacks a slice into individual arguments

Complete Example

package main

func sum(numbers ...int) int {
	total := 0
	for _, num := range numbers {
		total += num
	}
	return total
}

func lo(numbers ...interface{}) {
	for _, num := range numbers {
		println(num)
	}
}

func main() {
	result := sum(1, 2, 3, 4, 5)
	println("Sum:", result)
}

Rules and Constraints

1

Last Parameter Only

The variadic parameter must be the last parameter in the function signature.
// Valid
func print(prefix string, values ...int) {}

// Invalid - won't compile
func invalid(values ...int, suffix string) {}
2

Only One Variadic Parameter

You can only have one variadic parameter per function.
// Invalid - won't compile
func invalid(nums ...int, strs ...string) {}
3

Zero or More Arguments

Variadic functions accept zero or more arguments of the specified type.
sum()           // Valid - 0 arguments
sum(1)          // Valid - 1 argument
sum(1, 2, 3)    // Valid - 3 arguments

Real-World Examples

Many built-in Go functions use variadic parameters:
// fmt.Println accepts any number of arguments
fmt.Println("Hello", "World", 123, true)

// append accepts a slice and any number of elements
slice := []int{1, 2, 3}
slice = append(slice, 4, 5, 6)

// max/min functions (Go 1.21+)
max := max(5, 2, 8, 1, 9)  // Returns 9

Key Takeaways

Flexible Arguments

The ... syntax allows functions to accept any number of arguments.

Slice Inside

Variadic parameters are treated as slices within the function body.

Unpacking with ...

Use slice... to unpack a slice into individual arguments when calling.

Must Be Last

Variadic parameters must always be the last parameter in the signature.

Build docs developers (and LLMs) love