# Why Variadic Functions Matter
Variadic functions let you accept zero or morearguments of the same type. They make call sites cleaner for APIs like logging, formatting, aggregation, and helper utilities.
In Go, the variadic parameter is still just a slice inside the function body. This means all slice rules still apply: length checks, range loops, and potential mutation of shared backing arrays.
Real-World Analogyclick to expand
Think of a variadic function like a shopping basket checkout: you can bring 0 items, 3 items, or 100 items, but the cashier processes them using one collection internally.
The call site is flexible, but inside the function it's always a slice. That mental model avoids confusion.
# Basic Variadic Syntax
Use ...T on the last parameter to accept any number of values of type T.
func sum(nums ...int) int {
total := 0
for _, n := range nums {
total += n
}
return total
}
fmt.Println(sum(1, 2, 3))
fmt.Println(sum(1, 2, 3, 4, 5))
fmt.Println(sum())# Step-by-Step Semantics
Variadic must be last parameterfunc f(prefix string, vals ...int) is valid. Any parameter after ...int is invalid.
Inside function it is []TYou can use len(vals), for range, indexing, and all normal slice operations.
Passing a slice requires ...Use f(slice...) to spread. Without ..., types won't match.
# Spreading a Slice and append
Spreading is the bridge between existing slices and variadic APIs:
nums := []int{1, 2, 3, 4, 5}
fmt.Println(sum(nums...))
a := []int{1, 2}
b := []int{3, 4}
a = append(a, b...) // slice concat`append` is a built-in variadic function; always capture its returned slice because capacity growth can reallocate backing arrays.
# Mixed Parameters and Minimum-1 Pattern
You can combine fixed params with variadic params, and require at least one value by splitting first from rest.
func greet(prefix string, names ...string) {
for _, name := range names {
fmt.Printf("%s, %s!
", prefix, name)
}
}
func Max(first int, rest ...int) int {
max := first
for _, v := range rest {
if v > max {
max = v
}
}
return max
}# Real-World Example: Variadic Join
Implement a variadic wrapper similar to strings.Join.
package main
import (
"fmt"
"strings"
)
func Join(sep string, parts ...string) string {
if len(parts) == 0 {
return ""
}
return strings.Join(parts, sep)
}
func main() {
fmt.Println(Join(", ", "a", "b", "c"))
fmt.Println(Join("-", "2024", "01", "15"))
fmt.Println(Join(", "))
}⚡ Key Takeaways
- Use
...Tonly on the last parameter - Inside a variadic function, arguments are a slice of type
[]T - Use
slice...to spread existing slices append(a, b...)is idiomatic slice concatenation- For required-at-least-one APIs, use
first T, rest ...T