【问题标题】:Why golang slices internal designed like this?为什么golang切片内部是这样设计的?
【发布时间】:2015-01-10 02:47:46
【问题描述】:

代码:

func main() {

    a := []int{1, 2}
    printSlice("a", a)

    b := a[0:1]
    printSlice("b origin", b)

    b = append(b, 9)
    printSlice("b after append b without growing capacity", b)
    printSlice("a after append b without growing capacity", a)

    b = append(b, 5, 7, 8)
    printSlice("a after append b with grown capacity", a)
    printSlice("b after append b with grown capacity", b)

    b[0] = 1000
    printSlice("b", b)
    printSlice("a", a)      

}

func printSlice(s string, x []int) {
    fmt.Printf("%s len=%d cap=%d %v\n",
        s, len(x), cap(x), x)
}

输出:

a len=2 cap=2 [1 2]
b origin len=1 cap=2 [1]
b after append b without growing capacity len=2 cap=2 [1 9]
a after append b without growing capacity len=2 cap=2 [1 9]
a after append b with grown capacity len=2 cap=2 [1 9]
b after append b with grown capacity len=5 cap=6 [1 9 5 7 8]
b len=5 cap=6 [1000 9 5 7 8]
a len=2 cap=2 [1 9]

有趣的是在最后两行打印。我已经知道切片只是底层数组的一个窗口。在容量范围内对其进行重新切片时,两个切片共享相同的底层数组,但是当我对其进行重新切片以超出其容量时,两个切片具有不同的底层数组。但是为什么golang的设计者选择不将origin slice的底层数组改为新slice的底层数组,从而让两个slice的底层数组还是一样呢?在当前状态下,当我更改新重新切片的切片的某些元素的值时,我必须检查是否更改了底层数组以确定此操作是否对由它备份的其他切片有副作用(请参阅输出的最后两行)。我认为这很尴尬。

【问题讨论】:

  • 如果您担心“我必须检查 [...] 此操作是否对其他切片有副作用”,那么您做错了。
  • 我不明白反对意见。问题是 a) 完全有效 b) 准备充分(输入代码,几乎可运行,输出) c) 明确表述和 d) 这个问题有一个简单的答案。对于那些不赞成投票的人:请写下反对投票的原因。这将有助于 OP。

标签: go


【解决方案1】:

但是为什么golang的设计者选择不将origin slice的底层数组改成新slice的底层数组,从而让两个slice依然有相同的底层数组呢?

主要是,同一个数组的切片绝对可以出现在程序的任何地方——完全不同的函数、包等等。鉴于切片在内存中的布局方式,Go 必须“找到”共享数组的所有切片来更新它们;没办法。

其他一些数组列表实现(如 Python 列表)的方法是,您传递的实际上是一个 指针 指向类似 Go 切片的东西,如果两个变量持有“相同的列表” ",当您查看另一个变量时,也会显示使用一个变量的追加。这也有一些效率成本——另一个指针查找来做a[0]。在您确实需要在此处追加以充当那里的追加的情况下,您可以使用指向切片的指针。

如果需要,指向切片的指针会为您提供别名,但不提供子切片 - 要获得您要求的 一切,您需要一种我想不出的不同安排from in the wild 的示例(偏移量、长度和指向struct { capacity int; firstElem *type } 的指针)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-04-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-15
    • 2022-11-13
    • 1970-01-01
    • 2019-12-29
    相关资源
    最近更新 更多