切片切片参考

时间:2018-09-10 16:09:45

标签: go slice

我正在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个元素),而不是原始数组

有人可以揭露这两种情况有什么区别吗?

2 个答案:

答案 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对其进行了更深入的说明。