Welcome To Golang By Example

Pass Variable Number of Arguments to a function in Go (Golang)

Overview

In Go, a function that can accept a dynamic number of arguments is called a Variadic function. Below is the syntax for variadic function. Three dots are used as a prefix before type.

func add(numbers ...int)

The above function can be called with zero or more arguments

add()
add(1,2)
add(1,2,3,4)

The variadic param which is numbers, in this case, gets converted into a slice inside the function which can be iterated using range

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

If you already have a slice and you need to pass it as a variadic param then that can be done by adding three dots (…) after the argument while calling the function

var numbers := []int{2,3,5}
add(numbers...)

In case there is a need to pass variadic as well as non-variadic arguments to a function, then the non-variadic needs to be passed as initial arguments and variadic argument need to be the last.

func add(val string, numbers ...int)

The best example of a variadic function used in GO library is the fmt.Println() function. This is the signature of the function

func Println(a ...interface{}) (n int, err error) 

While using variadic functions there can be a couple of cases related to the variadic argument.

Different number of parameters but of the same type

The above case can easily be handled using variadic functions. Notice in below code the parameter is of one type i.e. int.

package main

import "fmt"

func main() {
    fmt.Println(add(1, 2))
    fmt.Println(add(1, 2, 3))
    fmt.Println(add(1, 2, 3, 4))
}

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

Output:

3
6
10

Different number of parameters and of different types

This case can be handled using both variadic function and empty interface

package main

import "fmt"

func main() {
    handle(1, "abc")
    handle("abc", "xyz", 3)
    handle(1, 2, 3, 4)
}

func handle(params ...interface{}) {
    fmt.Println("Handle func called with parameters:")
    for _, param := range params {
        fmt.Printf("%v\n", param)
    }
}

Output:

Handle func called with parameters:
1
abc
Handle func called with parameters:
abc
xyz
3
Handle func called with parameters:
1
2
3
4

We can also use a switch case to get the exact parameters and use them accordingly. See the below example.

package main

import "fmt"

type person struct {
    name   string
    gender string
    age    int
}

func main() {
    err := addPerson("Tina", "Female", 20)
    if err != nil {
        fmt.Println("PersonAdd Error: " + err.Error())
    }
    
    err = addPerson("John", "Male")
    if err != nil {
        fmt.Println("PersonAdd Error: " + err.Error())
    }
     
    err = addPerson("Wick", 2, 3)
    if err != nil {
        fmt.Println("PersonAdd Error: " + err.Error())
    }
}

func addPerson(args ...interface{}) error {
    if len(args) > 3 {
        return fmt.Errorf("Wront number of arguments passed")
    }
    p := &person{}
    //0 is name
    //1 is gender
    //2 is age
    for i, arg := range args {
        switch i {
        case 0: // name
            name, ok := arg.(string)
            if !ok {
                return fmt.Errorf("Name is not passed as string")
            }
            p.name = name
        case 1:
            gender, ok := arg.(string)
            if !ok {
                return fmt.Errorf("Gender is not passed as string")
            }
            p.gender = gender
        case 2:
            age, ok := arg.(int)
            if !ok {
                return fmt.Errorf("Age is not passed as int")
            }
            p.age = age
        default:
            return fmt.Errorf("Wrong parametes passed")
        }
    }
    fmt.Printf("Person struct is %+v\n", p)
    return nil
}

Note: Wherever the arg is not passed it is substituted as default.

Output:

Person struct is &{name:Tina gender:Female age:20}
Person struct is &{name:John gender:Male age:0}
PersonAdd Error: Gender is not passed as string