Golang variadic function Explained [Practical Examples]


GO

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, like sum, print, or anything you choose.
  • parameterName ...Type: Here’s the interesting part. The ... before the Type indicates that this function can accept any number of arguments of this type. Type can be any data type like int, 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.
NOTE:
You can't declare more params after a variadic params. i.e
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

 

Deepak Prasad

Deepak Prasad

He is the founder of GoLinuxCloud and brings over a decade of expertise in Linux, Python, Go, Laravel, DevOps, Kubernetes, Git, Shell scripting, OpenShift, AWS, Networking, and Security. With extensive experience, he excels in various domains, from development to DevOps, Networking, and Security, ensuring robust and efficient solutions for diverse projects. You can connect with him on his LinkedIn profile.

Can't find what you're searching for? Let us assist you.

Enter your query below, and we'll provide instant results tailored to your needs.

If my articles on GoLinuxCloud has helped you, kindly consider buying me a coffee as a token of appreciation.

Buy GoLinuxCloud a Coffee

For any other feedbacks or questions you can send mail to admin@golinuxcloud.com

Thank You for your support!!

Leave a Comment