golang- slice解析
Slice(切片)
定义
切片的概念在python
中也存在这个概念,在go
中,切片是对数组的一个连续片段的引用,所以切片是一个引用类型,它的内部结构包含地址
、长度
和容量
。
版本号:go version go1.20 darwin/arm64
runtime/slice.go type slice struct { array unsafe.Pointer len int cap int }
其中:
array
是底层数组指针,指向该切片的第一个元素len
是切片的长度cap
是切片的容量
变量声明
主要是使用make
关键字去进行切片的创建
// make([]T, len, cap) // len: 长度 // cap: 容量 // T: 类型 var s1 []int = make([]int, 5, 10) var s2 []int =make([]int, 5) 容量未声明,则与长度相等
s1
在初始化后,长度为5,容量为10,值为[0,0,0,0,0]
s2
在初始化后,长度为5,容量为5,值为[0,0,0,0,0]
扩容
扩容的前提是当前切片容量不足以容纳增加后的数据。
相关函数:
runtime/slice.go/growslice newcap := oldCap doublecap := newcap + newcap if newLen > doublecap { newcap = newLen } else { const threshold = 256 if oldCap < threshold { newcap = doublecap } else { // Check 0 < newcap to detect overflow // and prevent an infinite loop. for 0 < newcap && newcap < newLen { // Transition from growing 2x for small slices // to growing 1.25x for large slices. This formula // gives a smooth-ish transition between the two. newcap += (newcap + 3*threshold) / 4 } // Set newcap to the requested cap when // the newcap calculation overflowed. if newcap <= 0 { newcap = newLen } } }
-
如果当前容量扩充两倍后,仍然无法容纳新的数据,那么新的容量就为新的长度
oldlen+num
-
扩充两倍后,可以容纳新的数据,再判断
oldlen
是否>=
1024,大于则扩充1.25倍,小于则扩充两倍
函数传参
切片作为函数参数传递时,传递的是切片的引用,所以在函数内部修改切片的值,会影响到函数外部的切片值。
简单来说,切片a作为参数传递时,编译器会根据a的地址、长度、容量,创建一个新的切片b,然后将b作为参数传递给函数,所以在函数内部修改切片的值,a和b指向的底层数组x一致。修改b的元素,本质上修改底层数组的数据,所以a的值也会发生变化。
但如果切片b发生扩容,情况又不一样
更新切片
a=[]int{1,2,3,4,5} func UpdateSlice(b []int) { b[0] = 100 }
因为只是更新切片数据,修改b的元素,本质上修改底层数组的数据,a和b都还是指向同一块内存空间,所以a的值也会发生变化。
扩容切片
a=[]int{1,2,3,4,5} func GrowSlice(b []int) { b = append(b, []int{1, 2, 3, 4, 5, 6, 7, 8, 9}...) fmt.Println(b) }
b进行了append
操作,容量不足,发生扩容,编译器重新分配一块合适的内存空间,并修改了b
的指向,此时再去修改b
的值,不会影响到a
的值。
转载请标明,谢谢
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)