unexpected slice append behaviour

前端 未结 3 1819
臣服心动
臣服心动 2021-02-06 12:58

I encountered weird behaviour in go code today: when I append elements to slice in loop and then try to create new slices based on the res

3条回答
  •  醉酒成梦
    2021-02-06 13:08

    Don't assign append to anything other than itself.

    As you mention in the question, the confusion is due to the fact that append both changes the underlying array and returns a new slice (since the length might be changed). You'd imagine that it copies that backing array, but it doesn't, it just allocates a new slice object that points at it. Since i never changes, all those appends keep changing the value of backingArray[12] to a different number.

    Contrast this to appending to an array, which allocates a new literal array every time.

    So yes, you need to copy the slice before you can work on it.

    func makeFromSlice(sl []int) []int {
        result := make([]int, len(sl))
        copy(result, sl)
        return result
    }
    
    func main() {
        i := make([]int, 0)
        for ii:=0; ii<11; ii++ {
            i = append(i, ii)
        }
        j := append(makeFromSlice(i), 100)  // works fine
    }
    

    The slice literal behavior is explained because a new array is allocated if the append would exceed the cap of the backing array. This has nothing to do with slice literals and everything to do with the internals of how exceeding the cap works.

    a := []int{1,2,3,4,5,6,7}
    fmt.Printf("len(a) %d, cap(a) %d\n", a, len(a), cap(a))
    // len(a) 7, cap(a) 7
    
    b := make([]int, 0)
    for i:=1; i<8, i++ {
        b = append(b, i)
    }  // b := []int{1,2,3,4,5,6,7}
    // len(b) 7, cap(b) 8
    
    b = append(b, 1)  // any number, just so it hits cap
    
    i := append(b, 100)
    j := append(b, 101)
    k := append(b, 102)  // these work as expected now
    

提交回复
热议问题