Golang中的slice切片

232 阅读3分钟

这是我参与2022首次更文挑战的第12天,活动详情查看:2022首次更文挑战

切片

切片的内部实现

  1. 结构
  • 指向底层数组的指针
  • 长度len()
  • 容量cap()
  1. 切片与数组的区别
  • 初始化数组:var arrayName [length]type{}
  • 数组会默认把指定长度的值初始化为零值。
  1. 切片的初始化
var sliceName []type
  • 默认指针是nil,长度和容量都是0
sliceName := 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)
}