【问题标题】:where is the elements of slice will store if its size exceed the size of array?如果切片的大小超过数组的大小,切片的元素将存储在哪里?
【发布时间】:2014-04-27 05:51:18
【问题描述】:

我从数组 OrgArray 创建一个切片,如下所示

orgArray:=[3] string{"00","01","02"}
s := orgArray[:2]
s = append(s,"03")
s = append(s,"04")

's' 是我在数组 'orgArray' 上构建的切片

如果我打印 s 和 orgArray 的大小

fmt.Println(s) //[00 01 03 04]
fmt.Println(len(s),cap(s)) //4 6
fmt.Println(len(orgArray),cap(orgArray)) //3 3

len(s) 是 4 但 len(orgArray) 是 3 为什么?

追加时 slice 的额外元素存储在哪里?

【问题讨论】:

    标签: go


    【解决方案1】:

    The Go Programming Language Specification

    Appending to and copying slices

    如果 s 的容量不足以容纳附加值, append 分配一个新的,足够大的底层数组,适合 现有的切片元素和附加值。否则, append 重用底层数组。

    有关append 内置函数如何工作的更多详细信息,请阅读这篇博文:

    Arrays, slices (and strings): The mechanics of 'append'

    另外,请参阅这个 StackOverflow 答案,它说明了重新分配容量的计算:

    append complexity

    例如,

    package main
    
    import "fmt"
    
    func main() {
        orgArray := [3]string{"00", "01", "02"}
        fmt.Println("orgArray:", &orgArray[0], len(orgArray), orgArray)
        s := orgArray[:2]
        fmt.Println("       s:", &s[0], len(s), cap(s), s)
        s = append(s, "03")
        fmt.Println("       s:", &s[0], len(s), cap(s), s)
        s = append(s, "04")
        fmt.Println("       s:", &s[0], len(s), cap(s), s)
        fmt.Println("orgArray:", &orgArray[0], len(orgArray), orgArray)
    }
    

    输出:

    orgArray: 0x1052f2c0 3 [00 01 02]
           s: 0x1052f2c0 2 3 [00 01]
           s: 0x1052f2c0 3 3 [00 01 03]
           s: 0x1051a120 4 6 [00 01 03 04]
    orgArray: 0x1052f2c0 3 [00 01 03]
    

    【讨论】:

      【解决方案2】:

      slice 的结构是这样的:

      struct Slice
      { // must not move anything
       byte* array; // actual data
       uintgo len; // number of elements
       uintgo cap; // allocated number of elements
      };
      

      在您的示例中。解释如下:

      orgArray := [3]string{"00", "01", "02"}
      s := orgArray[:2]
      fmt.Println(len(s),cap(s))  //2,3 s is pointer to orgArray
      s = append(s, "03")
      fmt.Println(len(s),cap(s))  //3,3 cap is enough. s is pointer to orgArray
      s = append(s, "04")
      fmt.Println(len(s),cap(s))  //4,6 cap is not enough. regenerate array. then s point to the new array.
      

      【讨论】:

        【解决方案3】:
        s := orgArray[:2]
        

        由于您从原始切片中获取两个元素,然后再追加两个元素,因此长度变为 4。您可以在此处看到四个元素:

        fmt.Println(s) //[00 01 03 04]
        

        如果您想知道为什么容量为 6,那是因为容量以 2 的幂次方增加。因此,如果您有一个容量为 4 的切片并附加 5 个元素,则容量将变为 8。这与尝试重新分配追加时经常发生的切片的内存。

        【讨论】:

        • 但是底层数组 orgArray 的大小只有 3。我在数组 orgArray 上构建了切片 's'。
        • 切片不是数组——切片的大小是动态的,所以在添加对象时它会自动增长。非常类似于 C# 中的 List
        • @AlexMathew: orgArray 不够大,所以为s 分配了一个新的底层数组。详情见我的回答。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-10-12
        • 2021-04-25
        • 1970-01-01
        • 2015-07-28
        • 2012-08-27
        相关资源
        最近更新 更多