alramdein
alramdein

Reputation: 901

Why append slice in Go change the original slice?

I have this code:

// The input param is A := []int{3, 4, 5, 3, 7}
func someFunc(A []int) int {   
...
    ways := 0       
    i := 0
    for i < len(A) {
        if i+1 == len(A) || i == len(A) {
            fmt.Println("break")
            break
        }
        tempA := A // copy the slice by value

        fmt.Println("A: ", A)
        fmt.Println("tempA: ", A)
        fmt.Println()

        newArr = remove(tempA, i)

        if isAesthetic(newArr) {
            ways++
        }
        i++
    }
...
}

func remove(slice []int, s int) []int {
    return append(slice[:s], slice[s+1:]...)
}

Cosole output:

A:  [3 4 5 3 7]
tempA:  [3 4 5 3 7]

A:  [4 5 3 7 7]
tempA:  [4 5 3 7 7]

A:  [4 3 7 7 7]
tempA:  [4 3 7 7 7]

A:  [4 3 7 7 7]
tempA:  [4 3 7 7 7]

The variable A also changes while I just copy it by value into tempA. And also it is append() function, why the slice that used to append tempA also changed?

Upvotes: 3

Views: 2563

Answers (3)

shmsr
shmsr

Reputation: 4204

The type []T is a slice with elements of type T. What is a slice, then?

A slice is a descriptor of an array segment. It consists of a pointer to the array, the length of the segment, and its capacity (the maximum length of the segment).

Slice

The rectangle on left is the slice descriptor. The descriptor has 3 fields i.e., a pointer to the array, length, and capacity of array segment it is pointing to. Now, the pointer is pointing to a backing array on the right that actually stores the elements.

Suppose, you have a slice:

x := make([]byte, 5, 5)

Then it'd point to a backing array [5]byte as you can also see in the image.

Now, if you do:

y := x

thinking that would copy, but it wouldn't. It'd just create a new slice descriptor pointing to the same backing array that x was pointing to.

Hence, there's a built-in called copy which would help you copy (exactly what you want)

The copy built-in function copies elements from a source slice into a destination slice.

With copy you also get a new backing array that your destination site is pointing to.

To know more about slices, read this.

Upvotes: 3

Zombo
Zombo

Reputation: 1

You need to utilize the copy function:

package main
import "fmt"

func main() {
   a := []int{3, 4, 5, 3, 7}
   // bad
   b := a
   // good
   c := make([]int, len(a))
   copy(c, a)
   // CHANGES b and a!
   b = append(b[:1], b[2:]...)
   // c stays the same, a is messed up
   // [3 5 3 7 7] [3 5 3 7] [3 4 5 3 7]
   fmt.Println(a, b, c)
}

https://golang.org/pkg/builtin#copy

Upvotes: 0

blackgreen
blackgreen

Reputation: 44647

A slice variable of type []T, also called slice header, describes a contiguous section of a backing array. It is stored separately from the array data.

You can imagine it as a struct containing the length and a pointer to a certain item of the array (not necessarily the first one).

When you assign the value of a slice variable, you are actually assigning the length and pointer held by the slice header. So tempA ends up referencing the same backing array as A. Then indexing either will access the same underlying array item.

Recommended reading: https://blog.golang.org/slices

Upvotes: 3

Related Questions