首页 > 解决方案 > 切片切片参考

问题描述

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

有人可以阐明这两种情况有什么区别吗?

标签: goslice

解决方案


切片基本上是一个指向内存的指针,带有一些附加信息:

1) 当前使用的元素数量和

2)容量,即它可以占用的剩余长度。

在开始时,我们创建一个包含 6 个整数的切片,这使得 go 创建总大小为 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注意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

推荐阅读