我正在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 %v\n", 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个元素),而不是原始数组。
有人可以揭露这两种情况有什么区别吗?
答案 0 :(得分:5)
切片基本上是指向内存的指针,其中包含一些附加信息:
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,这是s = s[:0]
,它在位置0处具有长度为0的s
子切片。请注意{{1 }}相同,您可以省略第一个0。
s[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:]
答案 1 :(得分:0)
Leon 在Go的博客中向我致辞,他们恰好解决了我的问题。
以下代码段帮助我更好地理解了这个概念:
切片是数组段的描述符。它由指向数组的指针,段的长度及其容量(段的最大长度)组成。
切片不能增长到超出其容量。尝试这样做会导致运行时恐慌,就像在切片或数组的边界之外建立索引一样。 类似地,无法将切片重新切片为零以下以访问数组中的早期元素。
如果数组中包含更多元素,则可以扩展切片,但不能访问切片0以下的元素。 这是底层数组的窗口。 blog post对其进行了更深入的说明。