Search code examples
go

why pointer's address are changed when using slice expansion(...)?


func main() {
    arr := make([]*int, 5)
    for i := 0; i < len(arr); i++ {
        n := i
        arr[i] = &n
    }
    fmt.Println(arr) // [0x1400012a2d0 0x1400012a2d8 0x1400012a2e0 0x1400012a2e8 0x1400012a2f0]

    list := make([]*int, 0)
    list = append(arr[:1], arr[2:]...)
    fmt.Println(list) // [0x1400012a2d0 0x1400012a2e0 0x1400012a2e8 0x1400012a2f0]
    fmt.Println(arr)  // [0x1400012a2d0 0x1400012a2e0 0x1400012a2e8 0x1400012a2f0 0x1400012a2f0]
}

In last Println(), I want [0x1400012a2d0 0x1400012a2d8 0x1400012a2e0 0x1400012a2e8 0x1400012a2f0] , but I've got [0x1400012a2d0 0x1400012a2e0 0x1400012a2e8 0x1400012a2f0 0x1400012a2f0].

I don't understand why addresses are changed.

Is it happened because of slice expansion? Then, why this happened?

Please let me know about this question. Thanks.


Solution

  • See also “What is the idiomatic method and style of combining two slices in go?

    Let's simplify your program a bit:

    package main
    
    import "fmt"
    
    func main() {
        arr := make([]int, 0, 5)
        for i := 0; i < cap(arr); i++ {
            fmt.Println(arr, cap(arr)) /*
                [] 5
                [0] 5
                [0 1] 5
                [0 1 2] 5
                [0 1 2 3] 5
            */
            arr = append(arr, i)
        }
        fmt.Println(arr, cap(arr)) // [0 1 2 3 4] 5
    
        arr1 := arr[:1]
        arr2 := arr[2:]
    
        fmt.Println(arr1, cap(arr1)) // [0] 5
        fmt.Println(arr2, cap(arr2)) // [2 3 4] 3
    
        list := append(arr1, arr2[0], arr2[1], arr2[2])
        fmt.Println(list, cap(list)) // [0 2 3 4] 5
        fmt.Println(arr, cap(arr))   // [0 2 3 4 4] 5
    }
    

    What you are doing: You are creating one underlying array of size 5, with arr being a slice referencing to it. Then you create two slices arr1 and arr2 referencing to the same underlying array.

    When you append arr2 to arr1, the underlying array of arr1 has enough space (capacity), so the elements of arr2 are simply copied without reallocation. This is one way to delete an element from a slice, simply by doing arr = append(arr[:1], arr[2:]...).

    Since you keep you original arr around, referencing the same underlying array, you see the effects mirrored there.

    To learn more, read “Slices: usage and internals” on the Go blog.