切片的本质:
切片是一个引用类型,是基于数组类型做的一层封装,内部结构包含头部指针、长度、容量。
形象把切片理解一个“框” ,框住数组或map的一部分,只能框连续的元素,底层数组改了,切片也改了,切片可以再切片
切片长度 len(slice) 是切片框住的元素个数;切片的容量 cap(slice) 是底层数组从切片的第一个元素到最后一个元素的数量
切片支持自动扩容,里面的元素类型固定
切片之间是不能用==比较的,切片唯一合法的比较操作是和nil比较。判断切片是否为空要用len(slice) == 0来判断
一个nil值的切片并没有底层数组,一个nil值的切片的长度和容量都是0,但是一个长度和容量都是0的切片不一定是nil
声明切片:
var name []int // name==nil 为 true
切片初始化(若不初始化,切片=nil)
s1 := []string{"哈哈", "呵呵"} //底层初始化一个长度为2,容量为2的数组包装后返回
s1 := make([]int, 5, 10) //创建长度5容量10的切片,底层数组前5个元素为0,可以从第6个元素开始追加
s2 := make([]int, 0, 10) //创建长度0容量10的切片,长度为0有什么意义? append的时候从下标0开始追加
s2 := make([]int, 5) //如果不写容量,容量与长度一样
//由数组得到切片a1 := [...]int{0, 2, 3, 43, 6, 534, 32, 21, 23}
s1 := a1[0:4] //[0,2,3,43]
s2 := a1[:4] //a1[0:4]
s3 := a1[3:] //a1[3:len(a1)]
s4 := a1[:] //a1[0:len(a1)]
切片追加元素(扩容)
s1 := []string{"bj","sh","sz"} //长度=3,容量=3// 调用append函数追加。必须用原来的切片变量接收返回值,若追加元素超过容量,底层数组变了s1 = append(s1, "gz")//追加多个元素。操作之后,长度=3,容量=6s1 = append(s1, "hz", "cd")//批量增加ss的元素到s1中ss := []string{"wh", "xa", "sz"}s1 = append(s1, ss...) //"..."表示拆开
扩容逻辑:
if 申请容量>2倍旧容量 最终容量=申请容量
elif 旧切片长度<1024 最终容量=2倍旧容量
elif 旧切片长度>=1024 最终容量=旧容量+1/4
else 最终容量计算值溢出 最终容量=申请容量
使用copy()函数复制切片:
s1 := []int{1,3,5}
s2 := s1 //赋值,是引用赋值
var s3 = make([]int, 3)
copy(s3, s1) // copy成了两份
切片中删除元素
//没有封装好的删除元素的方法x1 := [...]int{1,3,5} //定义数组s1 := x1[:] //切片fmt.Println(s1, len(s1), cap(s1)) //[1,3,5] 3 3s1 = append(s1[:1], s1[2:]...) //删除下标为1的元素,容量还是3fmt.Println(s1, len(s1), cap(s1)) //[1,5] 2 3fmt.Println(x1) //[1,5,5]
切片遍历:
for i:=0;i<len(slice); i++{fmt.Println(s3[i])}for i,v := range slice{fmt.Println(i,v)}