What is the Variadic function in Go
Imagine you have a toolbox that can hold an indefinite number of tools. Sometimes you might put in a hammer and a screwdriver, other times maybe just a wrench, or maybe a whole bunch of tools. A variadic function in Go is like this toolbox, but instead of tools, it can accept a varying number of arguments (the pieces of data you pass to a function).
Basic Concept
In most functions, you define exactly how many arguments they need. For example, a function to add two numbers will always need two arguments. But what if you don't know how many numbers you'll want to add beforehand? This is where variadic functions shine. They allow you to pass in as many (or as few) arguments as you like.
How Can They Accept Variable Number of Arguments?
Let's use an example. Say you have a function sum()
that adds numbers. If it's variadic, you can write it like this:
func sum(numbers ...int) int {
// function body
}
The ...int
part is what makes it variadic. It tells Go, "Hey, I can take any number of int
arguments." When you call this function, you can do it like this:
sum(1, 2)
- just adding two numbers.sum(1, 2, 3, 4)
- adding four numbers.sum()
- adding no numbers, which is also okay!
The Last Parameter Rule
There's a rule in Go: if a function is going to be variadic, the part that accepts a variable number of arguments (like ...int
) must be the last parameter in the function definition. So, you can't have a function that looks like this:
func someFunction(...int, string) {
// This is not allowed in Go!
}
But you can have something like this:
func someFunction(a string, numbers ...int) {
// This is okay!
}
In this case, the function someFunction
takes a string a
and then any number of integers.
Basic Syntax of Defining a Variadic Function
The basic syntax for defining a variadic function in Go is similar to defining a regular function, with a little twist. Here's the general structure:
func functionName(parameterName ...Type) ReturnType {
// function body
}
func
: This is how you start defining any function in Go.functionName
: This is where you name your function, likesum
,print
, or anything you choose.parameterName ...Type
: Here’s the interesting part. The...
before theType
indicates that this function can accept any number of arguments of this type.Type
can be any data type likeint
,string
, etc.ReturnType
: This is the type of value your function will return. If your function doesn’t return anything, you can omit this part.
func functionName(param ...paramType, param2 paramtype){}
It will always be an error.
Example of Variadic Function in Go
// main.go
package main
import (
"fmt"
"os"
"strings"
)
func JoinString(separator string, data ...string) string {
var str string
if !(len(data) < 1) {
for i, v := range data {
str = str + v
if i != len(data)-1 {
str = str + separator
}
}
return str
}
return fmt.Sprintf("No elements passed %v", str)
}
func main() {
dataInput := os.Args[1:]
fmt.Printf("Results : %s", JoinString(",", dataInput...))
}
Output:- 1 With arguments provided
$go run main.go GoLinuxCloud AWS Google Azure
Results : GoLinuxCloud,AWS,Google,Azure
Output:- 2 Without arguments provided
$go run main.go
Results : No elements passed
Explanation:-
Our variadic function is func JoinString(separator string, data ...string) string {}
it accepts separator and list of data might be names of teams or other items. pack
operator is used at [data ...string]
while unpack
operator is used during printing the output fmt.Printf("Results : %s", JoinString(separator, dataInputs...))
[dataInputs...] is unpack operator which enable us to access values in a slice without creating a slice array and we don't have to use inbuilt append(slice,data..)
function to update our slice.
Passing Zero Arguments to a Variadic Function
One of the cool things about variadic functions is that you can call them even with zero arguments. When you do this, the function receives an empty slice of the specified type.
For the sum
function above, calling sum()
with no arguments means numbers
inside the function is an empty slice of int
. Since there's nothing to add up, the function will just return 0 (the initial value of total
).
Method:-1 Example of built-in variadic function in Go
In the Go Standard library Printf function from fmt package
, which accepts different data types at once, since it uses interface type. The interface allows us to pass unknown data types and numerous arguments. func Printf(format string, a ...interface{})
For example fmt.Printf()
// main.go
package main
import "fmt"
func main() {
var name string
var age int64
var salary float64
fmt.Print("Enter your firstName: \n ")
fmt.Scanf("%s", &name)
fmt.Print("Enter your age: \t ")
fmt.Scanf("%v", &age)
fmt.Print("Enter your hourly rate : \t ")
fmt.Scanf("%f", &salary)
// variadic function
fmt.Printf("My name is %s, %v years of age ,and hourly rate of $ %.2f salary.", name, age, salary)
}
Output:-
$go run main.go
Enter your firstName:
Doe
Enter your age:
30
Enter your hourly rate :
50
My name is Doe, 30 years of age, and hourly rate of $ 50.00 salary.
Explanation :-
We execute our main()function which let you enter several variable, we read those variable using fmt.Scanf() function from fmt package, we store the entered value into our variables name,age,salary
.
We print out the expected output using fmt.Printf()
function which accepts various arguments of different types as seen above.
Method:-2 Passing slice elements in Go variadic function
A slice is an array of unknown lengths, which can be manipulated by adding more elements. Using variadic function we can manipulate slice using append(slice,element...)
syntax.
Example: Adding elements in a slice
package main
import (
"fmt"
)
func sumIntegers(elem ...int64) int64 {
var sum int64
for i := range elem {
sum += elem[i]
}
return sum
}
func main() {
data := []int64{2, 4, 5, 7, 8}
sum := sumIntegers(data...)
fmt.Printf("Elements are %v and total is %v", data, sum)
}
Output
$ go run main.go
Elements are [2 4 5 7 8] and total is 26
Explanation :-
In the above we can unpack elements of a slicedata := []int64{2, 4, 5, 7, 8}
directly to a variadic function func sumIntegers(elem ...int64) int64 {}
using the data... unpacking to function. Under the hood data... creates a new slice and works well.
Example: Manipulating slice using variadic function
package main
import (
"fmt"
)
func product(num int64, elem ...int64) []int64 {
for key, val := range elem {
elem[key] = num * val
}
return elem
}
func main() {
data := []int64{2, 4, 5, 7, 8}
originalData := fmt.Sprintf("%v", data)
prod := product(3, data...)
fmt.Printf("Elements are %v and product is %v", originalData, prod)
}
Output
$ go run main.go
Elements are [2 4 5 7 8] and product is [6 12 15 21 24]
Explanation:-
In the above code, unpack(...)
operator is our main focus, instead of creating a slice to append those elements into it, Go underhood, creates a new slice that holds every change.
Method:-3 Passing non variadic parameters and mixing variadic
The variadic function accepts numerous parameters thus mixing non-variadic arguments i.e num int64
with variadic arguments/param str ...string
by putting the non variadic arguments before the variadic params i.e func functionName(param type, param2 ...param2Type) returnType{}
.
Example
// main.go
package main
import (
"fmt"
"os"
"strconv"
"strings"
)
func MixVariadic(age int64, salary float64, name ...string) string {
return fmt.Sprintf("My name is %s, %02d years of age ,and my hourly rate is $ %.2f.\n", strings.Join(name, " "), age, salary)
}
func main() {
age, _ := strconv.ParseInt(os.Args[1], 10, 64)
salary, _ := strconv.ParseFloat(os.Args[2], 64)
name := os.Args[3:]
fmt.Printf("Results : %s", MixVariadic(age, salary, name...))
}
Output
$ go run main.go 28 50 John Doe
Results: My name is John Doe, 28 years of age, and my hourly rate is $ 50.00.
Explanation:-
func MixVariadic(age int64, salary float64, name ...string) string {}
this is an example of mixed variadic and non variadic params. we have used the os package to read values from the terminal while executing our function and strconv package to convert the input params into our defined data type.
Frequently Asked Questions
What is a variadic function in Go?
A variadic function is a function that can accept a variable number of arguments. It's declared with an ellipsis ...
before the type of the last parameter. For example, func sum(nums ...int) int
is a variadic function that can take any number of int
arguments.
How do you call a variadic function with different numbers of arguments?
You can call a variadic function with any number of arguments by simply listing them. For example, sum(1, 2, 3)
or sum(4, 5)
.
Can a variadic function be called with no arguments?
Yes, you can call a variadic function without any arguments. For example, calling sum()
will work, and in the case of the sum
function, it will return 0.
How does a variadic function work internally in Go?
Internally, Go treats the arguments of a variadic function as a slice of the specified type. For example, in func sum(nums ...int)
, nums
is treated as []int
.
Can you pass a slice to a variadic function?
Yes, you can pass a slice to a variadic function by using the ...
operator after the slice. For example, if you have nums := []int{1, 2, 3}
, you can pass it to sum
like sum(nums...)
.
Can a variadic function have regular parameters as well?
Yes, a variadic function can have regular parameters, but the variadic part must be the last parameter. For example, func print(prefix string, nums ...int)
is valid.
What are some common use cases for variadic functions in Go?
Variadic functions are often used for functions that need to handle an arbitrary number of arguments, like formatting functions (fmt.Printf
), appending elements to slices (append
), and combining multiple strings (strings.Join
).
Can a variadic function return multiple values?
Yes, like any Go function, a variadic function can return multiple values. For instance, func sum(nums ...int) (int, error)
can return both a sum and an error.
How do you loop through arguments in a variadic function?
You can loop through arguments using a range loop. For example, in func sum(nums ...int) int
, you can loop through nums
with for _, num := range nums
.
Can you have more than one variadic parameter in a function?
No, Go only allows one variadic parameter per function, and it must be the last parameter.
Summary
In this article, we have learned that Variadic functions are essential when passing numerous numbers of unknown params, increasing the readability of the function and holding a temporary slice of variable which can be passed into a function without declaring it. For more information you can refer variadic function