切片究竟是什么
我们的宗旨是『知其然也必知其所以然』,说切片之前,不得不说一句go语言的数组,数组是一个固定长度的、容纳同类型元素的连续序列,比如,var a [8]int 就是定义了一个长度为8,类型为int类型的数组。
在Go语言中传递数组是纯粹的值拷贝,对于元素类型长度较大或元素个数较多的数组,如果直接以数组类型参数传递到函数中会有不小的性能损耗。有同学可能说我可以用数组指针类型做形参,对数组变量取地址传进去,可以吗?可以,能避免性能消耗,但是不如切片好使,继续往下看,带你知其所以然。
切片之于数组就像是文件描述符之于文件。数组退居幕后,承担起底层存储空间,而切片走向前台,给开发者一个更便捷使用数组的窗口。打开 GOROOT/src/runtime/slice.go,可以看到切片的类型定义:
看到切片的数据结构包含3个字段:
array:指向下层数组的指针;不用着急知道这个指针指向哪,后边验证代码中就知道了
len:切片的长度,即切片中当前元素的个数,即内置函数len()返回的值
cap:切片的最大容量,即内置函数cap()返回的值,cap >= len
所以,每个切片变量都是一个runtime.slice结构体类型的实例,接下来我们通过日常定义切片的集中方式,来慢慢揭开这个结构体的真身,尤其是数组指针。
定义切片的几种方式
数组的切片化 [low:high]
定义一个数组,a := [10]int {11,12,13,14,15,16,17,18,19,20}
通过数组定义切片,s := a[3:7]
此时,数组和切片的内存布局是这样的:
『知其然也必知其所以然』,是我们的宗旨,上代码:
既然说切片复用的数组的存储空间,那我们把切片结构中的数组指针以及指向数组的元素a[3]地址打出来看看,并通过切片来修改元素