切片
切片的内部实现
- 结构
- 指向底层数组的指针
- 长度len()
- 容量cap()
-
切片与数组的区别
初始化数组:var arrayName [length]type{}
数组会默认把指定长度的值初始化为零值。 -
切片的初始化
var sliceName []type
默认指针是nil,长度和容量都是0sliceName := make([]type,1,2)
使用make之后,会把切片初始化为0值,可以通过下标访问如果使用make([]type,2),会初始化len为2,cap为2的切片。
Javaer在这里需要注意,此时如果再使用append去添加元素到切片中,默认会有2个元素是0值。
错误示范:
slice := make([]int,6)
for _,value := range slice1{
slice = append(slice,value)
}
// 最后的结果可能是{0,0,0,0,0,0,slice1....}
正确解法:
slice := make([]int,0,6)
for _,value := range slice1{
slice = append(slice,value)
}
// 最后的结果是{slice1....}
注意事项:
Go不允许创建cap小于len的切片
切片定义时默认不会初始化底层数组,必须使用make初始化才可以用
把一个切片赋值给另一个切片,彼此共享数据结构
切片的切割
// 假设slice的容量是k
slice[i:j] 从i到j,长度是j-i,容量是k-i,相当于slice[i:j:k]
slice[i:] 从i到最后一个元素
slice[:j] 从0到j-1
slice[:] 从头到尾,相当于slice复制
注意事项
将切片切成两个切片时,共享底层数组,修改其中一个,也会影响到另外一个
如果两个切片数据没有交集,则修改就不会影响到另一个
切片的扩容
-
append函数会增加切片的长度,但是不一定会增加切片的容量,取决于长度有没有超过初始化的容量。
-
append时,如果超过了容量,会进行扩容。元素在1000以内时,都会成倍增长进行扩容。扩容后,新创建的切片跟原来切片的内存空间就不会共享了,修改切片元素的值,不会影响彼此的数据。
切片作为函数参数
切片是引用类型,作为函数的参数,函数内部的切片参数和外部的切片底层数组是同一个对象,函数内部修改的切片会影响外部的参数切片值(map也是一致的引用类型)。
for循环中的range
range循环创建了每个元素的副本,在for循环中修改value的值,不会影响原来的值。
迭代中,使用append和delete会影响到原来的切片或者map字典。
典型的易错点
for _,value := range slice{
fmt.Println(&value.A)
}
在这个例子中,for循环中每一次拿到的&valua.A均为第一次循环的那一个,新手很容易犯错。
每一次循环,都是重复利用了那一块内存,对那块内存进行循环赋值而已。
因此,解法是在循环中再用一个变量去接收value,或者调用函数,函数会进行copy,也就完成了解耦。
for _,value := range slice{
v1 := value
fmt.Println(&v1.A)
}