【问题标题】:Could anyone explain this strange behaviour of appending to golang slices谁能解释这种附加到 golang 切片的奇怪行为
【发布时间】:2015-02-18 12:24:54
【问题描述】:

下面的程序有意外的输出。

func main(){
    s:=[]int{5}
    s=append(s,7)
    s=append(s,9)
    x:=append(s,11)
    y:=append(s,12)
    fmt.Println(s,x,y)
}

输出:[5 7 9] [5 7 9 12] [5 7 9 12]

为什么x12的最后一个元素是?

【问题讨论】:

    标签: arrays go slice


    【解决方案1】:

    切片只是数组部分的一个窗口,它没有特定的存储空间。

    这意味着如果数组的同一部分有两个切片,则两个切片必须“包含”相同的值。

    这正是这里发生的事情:

    1. 当您执行第一个 append 时,您会在大小为 2 的基础数组上获得一个大小为 2 的新切片。
    2. 当您执行下一个append 时,您会得到一个大小为3 的新切片,但底层数组的大小为4append 通常会分配比立即需要的空间更多的空间,因此它不会t 需要在每次追加时分配)。
    3. 这意味着下一个append 不需要新数组。所以xy 都将使用与前面的切片s 相同的底层数组。你在这个数组的同一个槽中写入11 然后12,即使你得到两个不同的切片(记住,它们只是窗口)。

    您可以通过在每次追加后打印切片的容量来检查:

    fmt.Println(cap(s))
    

    如果你想在xy 中有不同的值,你应该做一个copy,例如这样:

    s := []int{5}
    s = append(s, 7)
    s = append(s, 9)
    x := make([]int,len(s))
    copy(x,s)
    x = append(x, 11)
    y := append(s, 12)
    fmt.Println(s, x, y)
    

    这里的另一种解决方案可能是强制s 切片后面的数组容量不大于所需的容量(从而确保append 后面的两个使用新数组):

    s := []int{5}
    s = append(s, 7)
    s = append(s, 9)
    s = s[0:len(s):len(s)]
    x := append(s, 11)
    y := append(s, 12)
    fmt.Println(s, x, y)
    

    另见Re-slicing slices in Golang

    【讨论】:

      【解决方案2】:

      dystroy 很好地解释了它。我喜欢为行为添加视觉解释。

      切片只是数组段的描述符。它由指向数组的指针 (ptr)、段的长度 (len) 和容量 (cap) 组成。

          +-----+                                                              
          | ptr |                                                              
          |*Elem|                                                              
          +-----+                                                              
          | len |                                                              
          |int  |                                                              
          +-----+                                                              
          | cap |                                                              
          |int  |                                                              
          +-----+ 
      

      所以,代码的解释如下;

      func main() {                                                           
                            +                                                 
                            |                                                 
        s := []int{5}       |  s -> +-----+                                   
                            | []int | ptr +-----> +---+                       
                            |       |*int | [1]int| 5 |                       
                            |       +-----+       +---+                       
                            |       |len=1|                                   
                            |       |int  |                                   
                            |       +-----+                                   
                            |       |cap=1|                                   
                            |       |int  |                                   
                            |       +-----+                                   
                            |                                                 
        s = append(s,7)     |  s -> +-----+                                   
                            | []int | ptr +-----> +---+---+                   
                            |       |*int | [2]int| 5 | 7 |                   
                            |       +-----+       +---+---+                   
                            |       |len=2|                                   
                            |       |int  |                                   
                            |       +-----+                                   
                            |       |cap=2|                                   
                            |       |int  |                                   
                            |       +-----+                                   
                            |                                                 
        s = append(s,9)     |  s -> +-----+                                   
                            | []int | ptr +-----> +---+---+---+---+           
                            |       |*int | [4]int| 5 | 7 | 9 |   |           
                            |       +-----+       +---+---+---+---+           
                            |       |len=3|                                   
                            |       |int  |                                   
                            |       +-----+                                   
                            |       |cap=4|                                   
                            |       |int  |                                   
                            |       +-----+                                   
                            |                                                 
        x := append(s,11)   |          +-------------+-----> +---+---+---+---+
                            |          |             | [4]int| 5 | 7 | 9 |11 |
                            |          |             |       +---+---+---+---+
                            |  s -> +--+--+  x -> +--+--+                     
                            | []int | ptr | []int | ptr |                     
                            |       |*int |       |*int |                     
                            |       +-----+       +-----+                     
                            |       |len=3|       |len=4|                     
                            |       |int  |       |int  |                     
                            |       +-----+       +-----+                     
                            |       |cap=4|       |cap=4|                     
                            |       |int  |       |int  |                     
                            |       +-----+       +-----+                     
                            |                                                 
        y := append(s,12)   |                        +-----> +---+---+---+---+
                            |                        | [4]int| 5 | 7 | 9 |12 |
                            |                        |       +---+---+---+---+
                            |                        |                        
                            |          +-------------+-------------+          
                            |          |             |             |          
                            |  s -> +--+--+  x -> +--+--+  y -> +--+--+       
                            | []int | ptr | []int | ptr | []int | ptr |       
                            |       |*int |       |*int |       |*int |       
                            |       +-----+       +-----+       +-----+       
                            |       |len=3|       |len=4|       |len=4|       
                            |       |int  |       |int  |       |int  |       
                            |       +-----+       +-----+       +-----+       
                            |       |cap=4|       |cap=4|       |cap=4|       
                            |       |int  |       |int  |       |int  |       
                            +       +-----+       +-----+       +-----+       
        fmt.Println(s,x,y)                                                    
      } 
      

      【讨论】:

        猜你喜欢
        • 2020-12-08
        • 2011-12-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-12-06
        相关资源
        最近更新 更多