golang切片的使用和内部细节 – By Andrew Gerrand
网上可以看到的golang slice博文很多,因为刚开始使用golang的时候, 偶尔需要确定一下slice容量扩展的细节,就会去Google一下,其实最生动,图文并茂的还是官网的这篇,这里记录一下, 以防哪天自己脑子秀逗了,又要回来确认什么的东西的时候从网上Google半天。
先来看两个例子:1
2
3
4
5
6
7
8
9
10
11
12package main
import (
"fmt"
)
func main(){
array := [4]int{1, 2, 3, 4}
slice := array[0:2]
newSlice := append(slice, 5)
newSlice[1] += 10
fmt.Println(slice)
// 这里会输出[1, 12],很神奇吧
}
再看另外一个例子
1 | package main |
我觉得参考博文中的图片,能很好的理解其原因,就是每个slice 有个len和cap属性,分别代表slice当前实际存储的元素个数和总容量, 向slice添加元素的时候,如果底层原本的存储未越界,多个slice可能会指向同一片空间,但是当越界后,就会开辟一块新空间,造成原本共用一片地址空间的多个slice分离。
在上面的例子1中, 从打印可以看出slice的cap空间大小是4, 所以 newSlice = append(slice,10)并未造成越界,会和slice公用一块空间,只是slice的len为2,所以打印的时候,只输出了2个元素,如果打印newslice就会看到3个元素。
例子2中,因为扩容了三次,引发了越界,所以newslice被指向了一片新的空间,原内容也复制了过去,之后,slice 和 newslice指向两片不同的地址,互相便不再有关联,对值的改变也就无法再互相影响了
摘一段博文中的原话:
A slice is a descriptor of an array segment. It consists of a pointer to the array, the length of the segment, and its capacity (the maximum length of the segment).
Our variable s, created earlier by make([]byte, 5), is structured like this:
The length is the number of elements referred to by the slice. The capacity is the number of elements in the underlying array (beginning at the element referred to by the slice pointer). The distinction between length and capacity will be made clear as we walk through the next few examples
As we slice s, observe the changes in the slice data structure and their relation to the underlying array: s= s[2:4]
Slicing does not copy the slice’s data. It creates a new slice value that points to the original array. This makes slice operations as efficient as manipulating array indices
ps:
Rob Pike大爷写的一个讲slice的博文:
Arrays, slices (and strings): The mechanics of ‘append’