A variadic function is one that can be called with varying
numbers of arguments.
The most familiar examples are fmt.Printf
and its variants.
Printf
requires one fixed argument at the beginning,
then accepts any number of subsequent arguments.
To declare a variadic function, the type of the final
parameter is preceded by an ellipsis, “...
”, which
indicates that the function may be called with any number
of arguments of this type.
func sum(vals ...int) int { total := 0 for _, val := range vals { total += val } return total }
The sum
function above returns the sum of zero or more
int
arguments.
Within the body of the function, the type of vals
is
an []int
slice.
When sum
is called, any number of values may be provided for
its vals
parameter.
fmt.Println(sum()) // "0" fmt.Println(sum(3)) // "3" fmt.Println(sum(1, 2, 3, 4)) // "10"
Implicitly, the caller allocates an array, copies the arguments into it, and passes a slice of the entire array to the function. The last call above thus behaves the same as the call below, which shows how to invoke a variadic function when the arguments are already in a slice: place an ellipsis after the final argument.
values := []int{1, 2, 3, 4} fmt.Println(sum(values...)) // "10"
Although the ...int
parameter behaves like a slice within the
function body, the type of a variadic function is distinct from the
type of a function with an ordinary slice parameter.
func f(...int) {} func g([]int) {} fmt.Printf("%T\n", f) // "func(...int)" fmt.Printf("%T\n", g) // "func([]int)"
Variadic functions are often used for string formatting.
The errorf
function below constructs a formatted error message
with a line number at the beginning.
The suffix f
is a widely followed naming convention
for variadic functions that accept a Printf
-style format string.
func errorf(linenum int, format string, args ...interface{}) { fmt.Fprintf(os.Stderr, "Line %d: ", linenum) fmt.Fprintf(os.Stderr, format, args...) fmt.Fprintln(os.Stderr) } linenum, name := 12, "count" errorf(linenum, "undefined: %s", name) // "Line 12: undefined: count"
The interface{}
type means that this function can accept any
values at all for its final arguments, as we’ll explain in
Chapter 7.
Exercise 5.15:
Write variadic functions max
and min
, analogous to
sum
.
What should these functions do when called with no arguments?
Write variants that require at least one argument.
Exercise 5.16:
Write a variadic version of strings.Join
.
Exercise 5.17:
Write a variadic function ElementsByTagName
that, given an HTML
node tree and zero or more names, returns all the elements that
match one of those names. Here are two example calls:
func ElementsByTagName(doc *html.Node, name ...string) []*html.Node images := ElementsByTagName(doc, "img") headings := ElementsByTagName(doc, "h1", "h2", "h3", "h4")