2

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?

alramdein
  • 810
  • 2
  • 12
  • 26
  • 2
    `tempA := A` does not copy a slice by value; it makes `tempA` point to the same contents as `A`, so modifying the contents `tempA` also modifies `A` – Eli Bendersky Jun 19 '21 at 01:58
  • @EliBendersky This https://www.geeksforgeeks.org/how-to-copy-an-array-into-another-array-in-golang/ reference is a scam then. So how to make it copy by value? So the `A` doesn't change when `tempA` change. – alramdein Jun 19 '21 at 02:03
  • 3
    A slice is a view of an array. Slices are not arrays. Assigning an array copies the array. Assigning a slice copies the slice header not the contents of it. – Burak Serdar Jun 19 '21 at 02:13
  • 2
    @alramdein See the copy section in [slice tricks](https://github.com/golang/go/wiki/SliceTricks#copy). – Charlie Tumahai Jun 19 '21 at 02:22
  • 2
    All data types in Go have a static size. If it doesn't have a constant number of elements, it's not an array. Slices are also statically sized, because the real data isn't stored "inside" the value (hence your issue). – Hymns For Disco Jun 19 '21 at 02:27
  • @alramdein: a slice variable is just a header (containing three elements: location of backing array if any, current length, and capacity). Using `tempA := A` copies the *slice header*, but does nothing with the backing array. The two slice headers now both use the same backing array. – torek Jun 19 '21 at 07:42

3 Answers3

3

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

blackgreen
  • 34,072
  • 23
  • 111
  • 129
3

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.

shmsr
  • 3,802
  • 2
  • 18
  • 29
  • Thank you for the detailed explanation. This answer almost perfect for me, but there is a point I miss that other user already answer it. Thank you. – alramdein Jun 19 '21 at 23:00
0

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

Zombo
  • 1
  • 62
  • 391
  • 407
  • The result of this is exactly like what I wanted to. I already use `copy()` to solve this, but I miss the point that I need to initialize it first with the same *length* of the slice that I want to copy. Thank you. – alramdein Jun 19 '21 at 22:58