通过切片创建新的切片
切片之所以被称为切片,是因为创建一个新的切片,也就是把底层数组切出一部分。通过切片创建新切片的语法如下:
slice[i:j]
slice[i:j:k]
其中
i
表示从slice
的第几个元素开始切j
表示切到第几个元素(不包括)。切片的长度为(j-i)
k
控制切片的容量(k-i)
,如果没有给定k
,则表示切到底层数组的最尾部。
下面是几种常见的简写形式:
slice[i:] // 从 i 切到最尾部
slice[:j] // 从最开头切到 j(不包含 j)
slice[:] // 从头切到尾,等价于复制整个 slice
让我们通过下面的例子来理解通过切片创建新的切片的本质:
// 创建一个整型切片
// 其长度和容量都是 5 个元素
myNum := []int{10, 20, 30, 40, 50}
// 创建一个新切片
// 其长度为 2 个元素,容量为 4 个元素
newNum := slice[1:3]
执行上面的代码后,我们有了两个切片,它们共享同一段底层数组,但通过不同的切片会看到底层数组的不同部分:
:::warning 注意,截取新切片时的原则是 “左含右不含”。
:::
所以 newNum
是从 myNum
的index=1
处开始截取,截取到 index=3
的前一个元素,也就是不包含 index=3
这个元素。所以,新的 newNum
是由 myNum
中的第 2
个元素、第 3
个元素组成的新的切片构,长度为 2
,容量为 4
。
切片 myNum
能够看到底层数组全部 5
个元素的容量,而 newNum
能看到的底层数组的容量只有 4
个元素。newNum
无法访问到底层数组的第一个元素。所以,对 newNum
来说,那个元素就是不存在的。
共享底层数组的切片
需要注意的是:
:::danger
现在两个切片 myNum
和 newNum
共享同一个底层数组。如果一个切片修改了该底层数组的共享部分,另一个切片也能感知到 (请参考前图):
:::
// 修改 newNum 索引为 1 的元素
// 同时也修改了原切片 myNum 的索引为 2 的元素
newNum[1] = 35
把 35 赋值给 newNum 索引为 1 的元素的同时也是在修改 myNum 索引为 2 的元素:
切片只能访问到其长度内的元素
切片只能访问到其长度内的元素,试图访问超出其长度的元素将会导致语言运行时异常。在使用这部分元素前,必须将其合并到切片的长度里。下面的代码试图为 newNum 中的元素赋值:
// 修改 newNum 索引为 3 的元素
// 这个元素对于 newNum 来说并不存在
newNum[3] = 45
上面的代码可以通过编译,但是会产生运行时错误:
panic: runtime error: index out of range