ProgrammingBackend Developer

Describe how variadic functions (functions with a variable number of arguments) are implemented in Go. How to properly declare, call them, and what pitfalls may occur when passing slices?

Pass interviews with Hintsage AI assistant

Answer

Variadic functions in Go allow you to take a variable number of arguments of the same type using the ellipsis syntax .... For example:

func sum(nums ...int) int { total := 0 for _, num := range nums { total += num } return total }

You can call such a function with any number of arguments:

result := sum(1, 2, 3, 4) // 10

Or pass a slice using the ... syntax:

numbers := []int{1,2,3} result := sum(numbers...) // 6

Nuances:

  • In the function, variadic parameters are treated as a slice ([]T). This means you can pass a pre-prepared slice.
  • Such parameters must always be the last in the list of function parameters.
  • If you pass a slice without ..., the function expects a regular parameter of type []T, not variadic.

Trick Question

What result will the following code give and why?

func printInts(nums ...int) { fmt.Printf("%#v ", nums) } ints := []int{1, 2, 3} printInts(ints)

Many mistakenly believe that this code will compile, but it will actually result in a compilation error:

Error: cannot pass a slice without ... to a variadic parameter.

Correct:

printInts(ints...) // OK

Examples of real errors due to ignorance of the nuances of the topic


Story

In a large project, a logging function was defined as func Log(msgs ...string). When passing a pre-prepared slice of strings, they simply called Log(strings) and received incorrect log output or a panic during execution. The reason was the absence of ..., causing the function to perceive a single argument of type []string, not separate strings.


Story

In one of the utility functions, it was necessary to process parameters, including a slice, and add more elements to it inside. They expected that ... would create a copy of the slice, not pass a reference — but inside the function, they modified the slice, which unexpectedly affected the caller, especially if the original slice was a reusable buffer.


Story

A developer implemented aggregation functions using a variadic parameter, but one of his colleagues incorrectly used the call syntax via casting: sum(interface{}([]int)), leading to implicit runtime errors, while it should have been explicitly sum(slice...). Ignorance of the nuances caused non-obvious bugs during massive refactorings.