@Golang亿点小细节之切片
你所忽略的,往往才是Bug的起源
谨言
不会slice,请不要尝试用go写算法!
简单聊聊slice
slice是一个长度可变的数组
go提供给slice的主要方法包括有切片[:]
,重组[:len()+n]
,复制copy()
,追加append()
slice的三个部分:指向相关数组的指针ptr
、当前数组长度len
、相关数组最大容量cap
在开始下面的内容前,请把这个图记在脑子里!
首先我们先来聊聊切片操作
x:=[]int{2,3,5,7,11}
y:=x[1:3] //y是通过对x进行切片得到的
但是切片不是进行拷贝,谨记,看图
切片操作是将产生的slice的ptr
指向原slice
的相关数组,同时通过len
和cap
产生一个形式上的切片
接下来聊聊重组和复制
改变slice
长度的过程叫做重组
sl = sl[0:len(sl)+1]
slice
重组只是改变了len
的值,切片可以反复扩展直到占据整个相关数组,即len=cap
,当len>cap
是就会发生扩容,扩容是使ptr
重新指向一个更大的相关数组
slice复制
func copy(dst, src []T) int copy
将类型为 T 的切片从源地址 src 拷贝到目标地址 dst,覆盖 dst 的相关元素,并且返回拷贝的元素个数。一般情况下复制可以使得两个slice拥有相互独立的相关数组。不过,源地址和目标地址可能会有重叠
我愿称append()
是go最大的坑
先给大家上一段代码
package main
import "fmt"
func main() {
x :=[]int{2,3,5,7,11}
y := x[1:3]
fmt.Println(y)
y=append(y, 10)
fmt.Println(y)
fmt.Println(x)
/*
output:
[3 5]
[3 5 10]
[2 3 5 10 11] //我的7怎么变成了10?????????
*/
}
细心的小伙伴会发现7->10
,原因是因为y.ptr
指向了x[1]
,所以append()
把7给覆盖掉了
在来一段代码
package main
import "fmt"
func main() {
x :=[]int{2,3,5,7,11}
y := x[1:] // 通过修改切片操作的长度,使得y在进行追加时会发生扩容
fmt.Println(y)
y=append(y, 10)
fmt.Println(y)
fmt.Println(x)
/*
output:
[3 5 7 11]
[3 5 7 11 10]
[2 3 5 7 11] // 我的7怎么又回来了???????
*/
}
上文中说到当slice
发生扩容时,会重新分配相关数组,所以y
的相关数组被重新分配了,但是这并不会影响x