Go ellipses
last modified October 30, 2026
In this article we show how to use the ellipses operator in Go. Three dots
(...) appear in variadic functions, in composite literals and in
the package patterns of the go tool.
All examples were compiled and run with Go 1.27.0.
Variadic parameters
A variadic function accepts any number of trailing arguments. The parameter is
declared with ... before its type, and inside the function it is
an ordinary slice.
package main
import "fmt"
func Sum(nums ...int) int {
total := 0
for _, n := range nums {
total += n
}
return total
}
func main() {
fmt.Println(Sum())
fmt.Println(Sum(1))
fmt.Println(Sum(1, 2, 3))
}
The function can be called with no arguments at all, in which case the slice is nil and the loop does not run. With one argument it behaves like a function of one parameter.
$ go run main.go 0 1 6
Passing a slice
A slice can be passed to a variadic parameter by appending ... to
the argument. Without the dots the slice is passed as a single value, which
does not match the parameter type.
package main
import "fmt"
func Sum(nums ...int) int {
total := 0
for _, n := range nums {
total += n
}
return total
}
func main() {
vals := []int{4, 5, 6}
fmt.Println(Sum(vals))
}
The compiler sees one argument of type []int where the function
expects int values. Writing Sum(vals...) expands the
slice into three arguments, so the program compiles and prints 15.
$ go build ./main.go:17:21: cannot use vals (variable of type []int) as int value in argument to Sum
Mixing fixed and variadic parameters
Only the last parameter of a function can be variadic. A function can combine fixed parameters with a variadic tail, which is useful for separators, prefixes and options.
package main
import "fmt"
func Join(sep string, parts ...string) string {
out := ""
for i, p := range parts {
if i > 0 {
out += sep
}
out += p
}
return out
}
func main() {
fmt.Println(Join("-", "a", "b", "c"))
fmt.Println("[" + Join(", ") + "]")
fmt.Println(Join(", ", []string{"x", "y"}...))
}
The separator is a fixed argument and the strings are variadic. The second call has no variadic arguments, so the result is an empty string between the brackets. The third call expands a slice.
$ go run main.go a-b-c [] x, y
append and fmt are variadic
Several functions of the standard library are variadic. append
takes one or more values, or another slice followed by ..., and
fmt.Println accepts any number of values of any type.
package main
import "fmt"
func main() {
nums := []int{1, 2, 3}
nums = append(nums, 4, 5)
fmt.Println(nums)
nums = append(nums, []int{6, 7}...)
fmt.Println(nums)
fmt.Println("values:", nums, "count:", len(nums))
}
The first append adds two values, the second adds all elements of
another slice. Printing several values in one call works because
Println is variadic as well.
$ go run main.go [1 2 3 4 5] [1 2 3 4 5 6 7] values: [1 2 3 4 5 6 7] count: 7
Inferring array length
In an array composite literal, [...] replaces the length and lets
the compiler count the elements. The result is still a fixed-size array, not a
slice.
package main
import "fmt"
func main() {
a := [...]int{3, 1, 4, 1, 5}
fmt.Println(len(a), a)
b := [...]string{2: "two", 0: "zero"}
fmt.Println(len(b), b)
c := [...]int{}
fmt.Println(len(c), c)
}
The first array has five elements and inferring gives it a length of five. With indexed elements the length is one more than the highest index, so the second array has three elements and an empty string in the middle. An empty literal produces an array of length zero.
$ go run main.go 5 [3 1 4 1 5] 3 [zero two] 0 []
Variadic function types
The three dots are part of the function type. A variable of type
func(...int) int can hold any function with that signature.
package main
import "fmt"
func Sum(nums ...int) int {
total := 0
for _, n := range nums {
total += n
}
return total
}
func main() {
var f func(...int) int = Sum
fmt.Println(f(7, 8))
fmt.Printf("%T\n", f)
}
The variable is assigned the Sum function and called like any
other function. The type printed by %T includes the dots.
$ go run main.go 15 func(...int) int
Wildcards in go commands
The go tool uses ... as a wildcard for package patterns.
./... means the current module and all its subpackages, while a
bare ... matches packages in the standard library and in the
module cache.
The pattern is handled by the go tool, not by the Go language, so it can be
used with build, vet, test and the other
package commands. Quoting is unnecessary because the shell passes the dots
through unchanged.
$ go list ./... com.zetcode/ellipses $ go test ./... ? com.zetcode/ellipses [no test files] $ go list ... | head -3 archive/tar archive/zip bufio
Source
The Go Programming Language Specification - function types
Go command - package patterns
In this article we have covered the ellipses operator in Go. We used it for variadic parameters and arguments, for mixing fixed and variadic parameters, for appending slices, for inferring array lengths, in function types and as a package wildcard in the go tool.
Author
List all Go tutorials.