Golang 中的重新切片
理解切片的行为可能会令人困惑,尤其是在涉及重新切片时。在此代码段中:
package main import "fmt" func main() { a := make([]int, 5) printSlice("a", a) b := make([]int, 0, 5) printSlice("b", b) c := b[:2] printSlice("c", c) d := c[2:5] printSlice("d", d) } func printSlice(s string, x []int) { fmt.Printf("%s len=%d cap=%d %v\n", s, len(x), cap(x), x) }
输出显示出意外的结果:
a len=5 cap=5 [0 0 0 0 0] b len=0 cap=5 [] c len=2 cap=5 [0 0] d len=3 cap=3 [0 0 0]
为什么 c 的容量为 5 而不是 2?要回答这个问题,我们需要了解 Golang 中切片的概念。
切片是对数组的轻量级引用。当我们创建切片时,我们提供范围操作(例如,[:2])来指定引用数组的开始和结束索引。但是,此范围操作不会创建基础数组的副本。相反,它会创建一个共享相同基础数据的新切片。
在给定的示例中,b 是一个容量为 5 的空切片。当我们将 c 创建为 b 的切片,范围为 [ :2],我们本质上是创建对 b 的前两个元素的引用。由于 b 的容量为 5,因此 c 可以扩展为最多包含 5 个元素,即使当前仅引用 2 个元素。这就是为什么 c 的容量为 5,尽管它的长度为 2。
此外,当我们将 d 创建为范围为 [2:5] 的 c 的切片时,我们实际上是在创建一个共享的切片与 b 相同的基础数据,但从索引 2 开始一直延伸到索引 5。由于 b 的容量为 5,因此 d 的容量为 3 (5-2).
下面的程序更清楚地说明了这种行为:
func main() { b := make([]int, 0, 5) c := b[:2] d := c[1:5] // equivalent to d := b[1:5] d[0] = 1 printSlice("c", c) printSlice("d", d) }
输出:
c len=2 cap=5 [0 1] // modifying d has modified c d len=4 cap=4 [1 0 0 0]
如您所见,修改 d 也可以修改了 c,证明 c 和 d 都是同一底层数组 b 上的窗口。
以上是为什么重新切片 Go 切片会导致意外的容量值?的详细内容。更多信息请关注PHP中文网其他相关文章!