赞
踩
struct Slice
{
byte* array; // actual data
uintgo len; // number of elements
uintgo cap; // allocated number of elements
};
我们知道slice是用来管理一个内存地址连续的内存空间,类似C++中的vector。由上面的定义可以看到,Slice在底层实现是一个结构体。
基本过程:
不断地向slice插入新的数据,len会不断增大,当len 大于 cap时,会申请更大的空间(据我观察,申请的空间是原来的2倍),然后把原来的数据复制到新的空间中。
由上面定义可知,slice底层有三个参数,所以使用make创建slice也需要指定3个参数。
s1 := make([]int, 3) // 有3个元素的切片, len为3, cap缺省此时等于len
s2 := make([]int, 3, 3) // 有3个元素的切片, len为3, cap为3
s3 := make([]int, 0, 3) // 有0个元素的切片, len为0, cap为3
其中s1和s2的定义方式,本质上是一致的。但是他们和s3不同,因为s1和s2已经有了3个元素,再插入一个新元素就会触发内存扩容,新的数据被插入第四个位置上。而s3内没有元素,下一个新元素被插入到第一个位置上。
语法格式:
s := data[low : high : max]
同样是三个参数,但是这三个参数都是data数组上的索引位置,言外之意就是:假设data数组容量为10,那么这三个参数最大为10,超过10就是不合法,就会编译报错(out of bounds for 10-element array)。
所以:
另外有一点需要说明,这样产生的切片底层指向data数组,修改s中数据,就会修改到data中的数据。
举例:
data := [10]int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9} // 创建数组,容量为10,同时包含10个元素
s1 := data[1:3:8] // 包含2个元素为1,2, cap为7
s2 := data[0:10:10] // 包含10个元素,cap为10
s3 := data[10:10:10] // 不包含任何元素,cap为0
s4 := data[0:] // 包含10个元素,cap为10
s5 := data[:10] // 包含10个元素,cap为10
刚才说了,指定的三个参数,都是原数组的索引位置,但是原数组10个元素,其索引范围为0-9,怎么能出现10呢?这个需要从指针的角度去理解,索引为10,其实就是第11个元素内存的起始指针,同时也是第10个元素内存的终止位置,这个位置是确实存在,没有越界。比如s3的定义方式,就很特殊,它的容量为0。
var s []int // 表示一个容量为0的切片
data := [10]int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9} // 创建数组,容量为10,同时包含10个元素
s1 := data[1:3:8] // 包含2个元素为1,2, cap为7
// 此时 s1包含2个元素,即s1[0]为1,s1[1]为2
// 往s1[2]写数据,注意s1的cap为7,即索引位置最大为6
s1[2] = 100
// 等价于s1[2]=100
// append表示在切片尾部插入新的数据,相当于C++中的push_back操作
s1 = append(s1, 100)
s2 := data[5:7]
s1 = append(s1, s2...) // 表示插入多个元素,因为s2有2个元素,后面要加三个点,注意语法格式
append的语法格式:
s1 = append(s1, 100)
s2 := append(s1, 100)
必须要接收append的返回值,否则编译报错。
为甚么一定需要一个值接收呢?
因为slice本质是一个结构体,不是指针,是值传递。当append对一个slice操作后,增加新的元素,它的len值就变化了,需要返回新的slice结构体,必须要接收。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。