Guobin
Guobin

Reputation: 19

Change golang slice in another function

I have a slice, if i remove one element from it directly in a main function the length of slice would be cut by one. But do the remove in another function and called it in main, the length of the slice is still keep origin. Who can explain it for me? Thanks!

package main

import "fmt"

func main() {
    a := []int{1, 2, 3, 4}
    i := 0

    //copy(a[i:], a[i+1:])
    //a[len(a)-1] = 0
    //a = a[:len(a)-1]
    //fmt.Println(a)    //outputs: [2 3 4], this is correct

    f(a, i)
    fmt.Println(a) //outputs: [2 3 4 0], this is wrong!
}

func f(a []int, i int) {
    copy(a[i:], a[i+1:])
    a[len(a)-1] = 0
    a = a[:len(a)-1]
    fmt.Println(a) //outputs: [2 3 4], here still correct
}

Go Playground Link

Upvotes: 0

Views: 3249

Answers (2)

Nitish Yadav
Nitish Yadav

Reputation: 55

Not providing new solution, just trying to explain why your program is behaving the way you asked:

Let us try to understand first how the built in function ‘copy’ works

Ref: [https://golang.org/pkg/builtin/#copy]

func copy(dst, src []Type) int

The copy built-in function copies elements from a source slice into a destination slice. (As a special case, it also will copy bytes from a string to a slice of bytes.) The source and destination may overlap. Copy returns the number of elements copied, which will be the minimum of len(src) and len(dst).

Two things: 1. 
First comment the line : //a[len(a)-1] = 0


  1. Second: As you are using the same array i.e as source and destination you are getting [2,3,4,4] as output as the destination array is {1,2,3,4} which got overwritten to {2,3,4,4(which is already present)}

you can try with different array’s to make it more clear to you

Upvotes: 0

Clément
Clément

Reputation: 804

The slice is passed by value, so changing it in your function f won't change it in function main. You can pass by pointer, like this:

package main

import "fmt"

func main() {
    a := []int{1, 2, 3, 4}
    i := 0

    f(&a, i)
    fmt.Println(a)    //outputs: [2 3 4], correct
}

func f(a *[]int, i int) {
    b := *a
    copy(b[i:], b[i+1:])
    // The following line seems pointless, but ok...
    b[len(b)-1] = 0
    b = b[:len(b)-1]
    fmt.Println(b)    //outputs: [2 3 4], here still correct
    *a = b
}

Go Playground

As suggested by @zerkms in the comments, you could also return the new slice, avoiding the use of pointers:

package main

import "fmt"

func main() {
    a := []int{1, 2, 3, 4}
    i := 0

    a = f(a, i)
    fmt.Println(a)
}

func f(a []int, i int) []int {
    copy(a[i:], a[i+1:])
    // The following line seems pointless, but ok...
    a[len(a)-1] = 0
    a = a[:len(a)-1]
    fmt.Println(a)     //outputs: [2 3 4], here still correct
    return a
}

Upvotes: 2

Related Questions