Zhe Chen
Zhe Chen

Reputation: 2957

Problems about `slice` and `append` in Go

I have written the following code. But I can't have it compiled. Here is my code:

package main

import "fmt"

func main() {
    tmp := make([]int, 10)
    for i := 0; i < 10; i++ {
        tmp[i] = i
    }
    res := mapx(foo, tmp)
    fmt.Printf("%v\n", res)
}

func foo(a int) int {
    return a + 10
}

func mapx(functionx func(int) int, list []int) (res []int) {
    res = make([]int, 10)
    for _, i := range(list) {
        append(res, functionx(i))
    }
    return
}

Meanwhile the error message is also very confusing: prog.go:21: append(res, functionx(i)) not used

But if I replace append(res, functionx(i))(line 21) with res = append(res, functionx(i)), it works quite well. Can anybody help me?

Thank you!

Upvotes: 10

Views: 18794

Answers (1)

peterSO
peterSO

Reputation: 166559

Appending to and copying slices

The variadic function append appends zero or more values x to s of type S, which must be a slice type, and returns the resulting slice, also of type S.

If the capacity of s is not large enough to fit the additional values, append allocates a new, sufficiently large slice that fits both the existing slice elements and the additional values. Thus, the returned slice may refer to a different underlying array.

Calls

In a function call, the function value and arguments are evaluated in the usual order. After they are evaluated, the parameters of the call are passed by value to the function and the called function begins execution. The return parameters of the function are passed by value back to the calling function when the function returns.

In Go, arguments are passed by value.

You need to write res = append(res, functionx(i)) so that you don't discard the new value for res, which refers to a different slice and, possibly, a different underlying array.

For example,

package main

import "fmt"

func main() {
    res := []int{0, 1}
    fmt.Println(res)
    _ = append(res, 2) // discard
    fmt.Println(res)
    res = append(res, 2) // keep
    fmt.Println(res)
}

Output:

[0 1]
[0 1]
[0 1 2]

Upvotes: 31

Related Questions