我正在Golang网站上进行游览,我正在尝试消化其中一个例子。目前尚不清楚它是如何工作的:
package main
import "fmt"
func main() {
s := []int{2, 3, 5, 7, 11, 13}
printSlice(s)
// Slice the slice to give it zero length.
s = s[:0]
printSlice(s)
// Extend its length.
s = s[:4]
printSlice(s)
// Drop its first two values.
s = s[2:]
printSlice(s)
}
func printSlice(s []int) {
fmt.Printf("len=%d cap=%d %vn", len(s), cap(s), s)
}
输出为:
len=6 cap=6 [2 3 5 7 11 13]
len=0 cap=6 []
len=4 cap=6 [2 3 5 7]
len=2 cap=4 [5 7]
在第一个切片之后,s = s[:0]
切片长度为 0。然后还有另一块s = s[:4]
.虽然长度为 0,但这似乎有效。但是这是怎么发生的呢?底层阵列不应该从s
访问吗?
更让我困惑的是,下次我们切片时,s = s[2:]
我们切片的是 s 的旧值(即 4 个元素(而不是原始数组。
有人可以说出一些线索吗 两种情况有什么区别?
切片基本上是指向内存的指针,其中包含一些附加信息:
1(当前使用的元素数量和
2(容量,即它可以占用的剩余长度。
一开始,我们创建一个包含 6 个整数的切片,这使得创建总大小为 6 的底层 int 数组。
here is your memory locations with addresses (content does not matter here)
* * * * * *
[0][1][2][3][4][5]
^
s points to the start of the memory
len(s) = 6
cap(s) = 6
接下来我们说:使这个切片的len
为 0,这是在位置 0 处取一个长度为 0 的s
子切片的s = s[:0]
。请注意,s[0:0]
相同,则可以省略前 0。
[0][1][2][3][4][5]
^
s still points to the start of the memory
len(s) = 0
cap(s) = 6
由于容量仍然相同,我们不妨通过说 4 来制作长度s = s[:4]
.
* * * *
[0][1][2][3][4][5]
^
s still points to the start of the memory
len(s) = 4
cap(s) = 6
然后我们通过执行s = s[2:]
.
* *
[0][1][2][3][4][5]
^
s now points to the original address plus two!
len(s) = 2
cap(s) = 4
Leon向我介绍了Go的博客文章,他们准确地解决了我的问题。
这是帮助我更好地理解这个概念的片段:
切片是数组段的描述符。它由指向数组的指针、段的长度及其容量(段的最大长度(组成。
切片不能超出其容量。尝试这样做会导致运行时崩溃,就像在切片或数组边界之外编制索引一样。同样,切片不能重新切片到零以下以访问数组中的早期元素。
如果数组中有更多元素,则可以扩展切片,但它无法访问切片 0 以下的元素。它是底层阵列的窗口。博客文章对此进行了更深入的解释。