This is the 9th day of my participation in Gwen Challenge

Hi, I’m @Luo Zhu

This article was first published on luo Zhu’s official website

This article was translated from Golang Tutorial Series

This article synchronizes in the public account “luo Zhu early teahouse”, reprint please contact the author.

Creation is not easy, form a habit, quality three even!

What is a function with variable parameters?

In general, functions only take a fixed number of arguments. A function with mutable parameters is a function that takes mutable parameters. If the last argument of a function definition is preceded by an ellipsis… , the function can take any number of arguments to that parameter.

Only one function can have a variable last argument. We will learn why this is the case in the next section of this tutorial.

grammar

func hello(a int, b ...int){}Copy the code

In the above function, argument B is mutable because it is prefixed with an ellipsis, and it can take any number of arguments. This function can be called using syntax.

hello(1.2) // Pass an argument '2' to b
hello(5.6.7.8.9) // Pass parameters 6, 7, 8, and 9 to b
Copy the code

In the code above, we call Hello with argument B being an argument 2. In 1, we call hello, parameter B is an argument 2, and we pass four arguments 6, 7, 8, 9 to B on the next line.

It is also possible to pass zero arguments to a variable function.

hello(1)
Copy the code

In the code above, when we call Hello, the argument to b is zero. That’s good.

Now I think you see why variable arguments should only be in the last one.

Let’s try to make the first argument to the Hello function variable.

The syntax will look like this

func hello(b ...int, a int){}Copy the code

In the above function, it is impossible to pass arguments to argument A, because whatever argument we pass will be assigned to the first argument, b, because it is an argument. Therefore, variable arguments can only appear at the end of the function definition. Syntax error: cannot use… With non-final parameter b.

Examples and see how variable functions work

Let’s create our own variable function. We will write a simple program to find if an integer exists in the list of integers entered.

package main

import (
    "fmt"
)

func find(num int, nums ...int) {
    fmt.Printf("type of nums is %T\n", nums)
    found := false
    for i, v := range nums {
        if v == num {
            fmt.Println(num, "found at index", i, "in", nums)
            found = true}}if! found { fmt.Println(num,"not found in ", nums)
    }
    fmt.Printf("\n")}func main(a) {
    find(89.89.90.95)
    find(45.56.67.45.90.109)
    find(78.38.56.98)
    find(87)}Copy the code

Run in playground

Func find(num int, nums… Int) accepts an indefinite number of nums. In find, nums is of type []int, which is a slice of an integer.

A variable function works by converting the number of variable arguments into a slice of the type of the variable argument. For example, in the above program, the find function takes 89, 90, 95 variables. The lookup function expects a variable int argument. Therefore, these three arguments will be converted by the compiler to a slice of type int []int{89, 90, 95}, which will then be passed to find.

The for loop is based on f. The for loop runs on the NUMS slice, printing out the position of num if it exists in the slice. If not, the number is not found.

The output of the above program.

type of nums is []int
89 found at index 0 in[89, 90, 95]type of nums is []int
45 found at index 2 in [56 67 45 90 109]

type of nums is []int
78 not found in56, 98 [38]type of nums is []int
87 not found in  []
Copy the code

In the above program, the find call takes only one argument. We have no input to the variable nums… The int argument passes any argument. As discussed earlier, this is perfectly legal, in which case NUMs will be a nil slice of length and capacity zero.

Slicing parameters vs variable parameters

We should definitely have a question on your mind right now. In the previous section, we learned that the variable argument to a function actually transforms a slice. So why use a variable function when we can do the same thing with slices? I rewrote the above program with slices below.

package main

import (
    "fmt"
)

func find(num int, nums []int) {
    fmt.Printf("type of nums is %T\n", nums)
    found := false
    for i, v := range nums {
        if v == num {
            fmt.Println(num, "found at index", i, "in", nums)
            found = true}}if! found { fmt.Println(num,"not found in ", nums)
    }
    fmt.Printf("\n")}func main(a) {
    find(89And []int{89.90.95})
    find(45And []int{56.67.45.90.109})
    find(78And []int{38.56.98})
    find(87And []int{})}Copy the code

Run in playground

Here are the advantages of using variable parameters instead of slicing.

  1. There is no need to create a fragment every time a function is called. If you look at the program above, we create a new shard every time the function is called. This additional fragment creation can be avoided when using variable functions.
  2. In the above program, we created an empty slice to satisfyfindThe signature of the function. In the case of parametric variable functions, this is not necessary at all. When using variable functions, this line can be used directlyfind(87).
  3. I personally find programs with variable functions more readable than programs with slicing 🙂

Append is a variable function

Have you ever wondered how the library’s append function appends values to a slice that can take any number of arguments? That’s because it’s a function of variables.

func append(slice []Type, elems ... Type) []Type
Copy the code

This is the definition of the append function. In this definition, elems is a variable parameter. So Append can accept a different number of arguments.

Pass a slice to a function with variable arguments

Let’s pass a slice to a variable function and find out what happens in the following example.

package main

import (
    "fmt"
)

func find(num int, nums ...int) {
    fmt.Printf("type of nums is %T\n", nums)
    found := false
    for i, v := range nums {
        if v == num {
            fmt.Println(num, "found at index", i, "in", nums)
            found = true}}if! found { fmt.Println(num,"not found in ", nums)
    }
    fmt.Printf("\n")}func main(a) {
    nums := []int{89.90.95}
    find(89, nums)
}
Copy the code

Run in playground

We pass a slice to a function that expects a variable number of arguments.

This is not feasible. /prog. Go :23:10: Cannot use nums (type []int) as type int in argument to find.

Why does this happen? Well, that’s a straightforward question. The find signature is provided below.

func find(num int, nums ...int)
Copy the code

By the definition of the variable function, nums… Int means that it will take a variable number of arguments of type int.

In the above program, nums is a slice of []int that is passed to find, which expects an int argument. As we’ve already discussed, these variable arguments will be converted to a slice of type int, because find expects the variable int argument. In this case, nums is already a []int shard, and the compiler is trying to create a new []int, that is, the compiler is trying to do:

find(89And []int{nums})
Copy the code

This will fail because nums is a []int and not an int.

So is there a way to pass a slice to a variable function? The answer is yes.

There is a syntactic sugar that can be used to pass a shard into a variable function. You have to use ellipses… As a suffix for slices, if this is done, slices are passed directly to the function without the need to create a new slice.

In the above program, if you replace find(89, nums) with find(89, nums…) , the program will compile and print the following output.

type of nums is []int
89 found at index 0 in [89 90 95]
Copy the code

The following is the complete scheme for your reference.

package main

import (
    "fmt"
)

func find(num int, nums ...int) {
    fmt.Printf("type of nums is %T\n", nums)
    found := false
    for i, v := range nums {
        if v == num {
            fmt.Println(num, "found at index", i, "in", nums)
            found = true}}if! found { fmt.Println(num,"not found in ", nums)
    }
    fmt.Printf("\n")}func main(a) {
    nums := []int{89.90.95}
    find(89, nums...)
}
Copy the code

Run in playground

Is that clear?

Just make sure you know what you’re doing when you modify a slice in a function with variable parameters.

Let’s look at a simple example.

package main

import (
    "fmt"
)

func change(s ...string) {
    s[0] = "Go"
}

func main(a) {
    welcome := []string{"hello"."world"}
    change(welcome...)
    fmt.Println(welcome)
}
Copy the code

Run in playground

What do you think the output of the above program will be? If you think it’s going to be Go World, congratulations! You’ve understood functions and slicing with variable parameters. If you get it wrong, no big deal, let me explain how we got this output.

In the above program, we used syntactic sugar… And pass the slice as a variable parameter to the change function.

As we have already discussed, if using… , the Welcome slice itself will be passed as a parameter, without creating a new slice. So welcome is passed as an argument to the change function.

In the change function, the first element of the shard is changed to Go. Therefore, the program outputs

[Go world]
Copy the code

There is also a program to learn about functions with variable parameters.

package main

import (
    "fmt"
)

func change(s ...string) {
    s[0] = "Go"
    s = append(s, "playground")
    fmt.Println(s)
}

func main(a) {
    welcome := []string{"hello"."world"}
    change(welcome...)
    fmt.Println(welcome)
}
Copy the code

Run in playground

I want to use this as an exercise for you to figure out how the above program works

So much for functions with variable parameters. Thank you for reading. Please leave your valuable feedback and comments. Have a nice day.