The Mail.ru Cloud Solutions team hastranslated an article about variadic functions in Go. Its author explains how variadic functions differ from ordinary functions and how to create them.
What is a variadic function
A function is a piece of code designed to perform a specific task. The function is passed one or more arguments, and it returns one or more results.
Variant functions are the same as regular functions , but they can take an infinite or variable number of arguments.
func f(elem ...Type)
This is what the typical variadic function syntax looks like. The operator
...
, also known as the boxing operator, tells Go to store all type arguments Type
in a parameter elem
. In other words, Go creates a variable elem
with a type []Type
, that is, a slice. And all the arguments passed to the function are stored in the slice elem
.
Let's see an example of a function
append()
.
append([]Type, args, arg2, argsN)
The function
append
expects the first argument to be a slice of type Type
followed by an arbitrary number of arguments. But how do you add a slice s2
to a slice s1
?
From the definition of the function,
append()
it follows that we cannot pass two slices to it - there is Type
only one type argument . Therefore, we use the unboxing operator ...
to unpack the slice into a series of arguments. They can then be passed to the function append
.
append(s1, s2...)
...
denote both the packing operator and the unpacking operator. The unboxing operator always appears after the variable name.
In our example, the slices
s1
and s2
the same type. We usually know the parameters of a function and the number of arguments it takes. How does a function accept
know how many parameters have been passed to it?
If you look at the function declaration
append
, you can see the expression elems ...Type
. It packs all arguments, starting with the second, into a slice elems
.
func append(slice []Type, elems ...Type) []Type
Only the last argument in a function declaration can be variadic.
Hence, the first argument to the function
append
is only a slice, since it is defined as a slice. All subsequent arguments are packed into one argument named elems
.
Now let's see how to create your own variadic function.
How to create a variadic function
As mentioned above, a variadic function is a regular function that takes a variable number of arguments. To do this, you need to use the boxing operator
...Type
.
Let's write a function
getMultiples
with a first factor
type argument int
(multiplication factor) and a variable number of additional type arguments int
. They will be packed into a slice args
.
Use to
make
create an empty slice, it is the same size as the slice args
. Using a loop for range
, multiply the slice elements args
by factor
. We put the result into a new empty slice multiples
, which we will return as a result of the function.
func getMultiples(factor int, args ...int) []int {
multiples := make([]int, len(args))
for index, val := range args {
multiples[index] = val * factor
}
return multiples
}
This is a very simple function, apply it inside a block
main()
.
func main() {
s := []int{10, 20, 30}
mult1 := getMultiples(2, s...)
mult2 := getMultiples(3, 1, 2, 3, 4)
fmt.Println(mult1)
fmt.Println(mult2)
}
https://play.go.org/p/BgU6H9orhrn
What happens if, in the example above, you pass the slice s to the function
getMultiples
as the second argument? The compiler will report an error:getMultiples
it cannot be useds (type [] int)
as a typein an argumentint
. This is because the slice has a type that[]int, getMultiples
expects parameters fromint
.
How a slice is passed to a variadic function
Slice is a reference to an array. So what happens when you pass a slice to a variadic function using the unboxing operator? Does Go create a new slice
args
or does it use an old slice s
?
Since we have no comparison tools
args == s
, we need to change the slice args
. Then we find out if the original slice has changed s
.
https://play.go.org/p/fbNgVGu6JZO
In the example above, we slightly changed the function
getMultiples
. And instead of creating a new slice, we assign the calculation results to the elements of the slice args
, replacing the incoming elements with the multiplied elements.
As a result, we see that the values โโof the original slice
s
have changed. If you pass arguments to the variadic function via the unboxing operator, then Go uses references to the data array underlying the original to create a new slice. Be careful not to make a mistake, otherwise the original data will change as a result of calculations.
Good luck!
What else to read: