1. 程式人生 > >Variadic function in Go

Variadic function in Go

What is a variadic function?

As we have seen in a functions lesson, a function is a piece of code dedicated to do a particular job. A function takes one or many arguments and may return one or many values. Variadic functions are also functions but they can take infinite or variable number of arguments

. Sounds stupid but we have seen this in slices lesson when append function accepted variable number of arguments.

func f(elem ...Type)

A typical syntax of a variadic function looks like above. ... operator called as pack operator instructs go to store all arguments of type Type in elem parameter. With this syntax, go creates elem

variable of type []Type which is a slice. Hence, all arguments passed to this function is stored in a elem slice.

Let’s take an example of append function.

append([]Type, args, arg2, argsN)

append function expects first argument to be a slice of type Type, while there can be variable number of arguments after that. If we have a slice s2

that we want to append to a slice s1, how that will work?

As from append function syntax, we can’t pass another slice as argument, it has to be one or many arguments of type Type. Hence, instead we will use unpack operator ... to unpack slice into the series of arguments (which is acceptable by append function).

append(s1, s2...)
... signifies both pack and unpack operator but if three dots are in the tail position, it will unpack a slice.

Here s1 and s2 are two slices of same type. Usually we know function parameters and how many arguments a function can accept. Then how append function knows how many parameters has passed to it?

If you look at the signature append function,

func append(slice []Type, elems ...Type) []Type

You will see elems ...Type which means pack all incoming arguments into elems slice after first argument.

One important thing to notice is that only the last argument of a function is allowed to be variadic.

So the first argument to append function will be a slice because it demands a slice but later arguments will be packed into one argument elems. I hope that makes it clear and now let’s look at creating your own variadic function.

☛ How to create a variadic function?

As discussed earlier, variadic function nothing but a function that accepts variable number of arguments. To make a function accept variable number of arguments, we need to use pack operator ...Type.

unpack operator ends with ... like slice... while pack operator starts with ... like ...Type.

Let’s write getMultiples function whose first argument is factor of type int which is a factor of multiplication and later variable arguments (hence variadic arguments) of type int are packed into slice args.

In this function, we are creating an empty slice using make function with length equal to length of args which is a slice. Using for range, we are multiplying factor with elements of args and saving them in multiples. Later, we return slice multiples.

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 as simple as it can get. We can implement this function inside main function like

func main() {	s := []int{10, 20, 30}	mult1 := getMultiples(2, s...)	mult2 := getMultiples(3, 1, 2, 3, 4)
	fmt.Println(mult1)	fmt.Println(mult2)}
What will happen if in above example, you pass slice s directly to getMultiples function as second argument. Obviously, compiler will complain cannot use s (type []int) as type int in argument to getMultiples because slice is type of []int and getMultiples expects parameter(s) of int.

☛ How slice is passed to a variadic function?

As slice is reference to an array, what happens when you pass slice to a variadic function using unpack operator. Does go creates new slice args or keeps the same slice s. Since, we don’t have any tool to compare, args == s, we need to mutate args slice itself to check if original slice s mutated.

In above program, we have modified getMultiples variadic function slightly and instead of creating new slice, we assigned multiplication values to args itself replacing incoming elements with multiplied elements.

From above result, we can see values of slice s changed. This means, go in case of slice when passed to variadic function using unpack operator, will use underneath array to build new slice. So, be careful.