golang语法专题:slice、map
参考:
https://blog.csdn.net/weixin_52690231/article/details/124827013(Go1.17、1.18源码分析slice扩容规则)
https://www.jianshu.com/p/7782d82f5154(go map实现原理)
https://www.cnblogs.com/qcrao-2018/p/10903807.html(深度揭秘go map)
slice
源码路径:go/src/runtime/slice.go
Go1.17源码分析slice扩容规则
func growslice(et *_type, old slice, cap int) slice { ... newcap := old.cap doublecap := newcap + newcap if cap > doublecap { newcap = cap } else { if old.cap < 1024 { newcap = doublecap } else { // Check 0 < newcap to detect overflow // and prevent an infinite loop. for 0 < newcap && newcap < cap { newcap += newcap / 4 } // Set newcap to the requested cap when // the newcap calculation overflowed. if newcap <= 0 { newcap = cap } } } ... }
代码的扩容策略可以简述为以下三个规则:
1.当期望容量 > 两倍的旧容量时,直接使用期望容量作为新切片的容量
2.如果旧容量 < 1024(注意这里单位是元素个数),那么直接翻倍旧容量
3.如果旧容量 > 1024,那么会进入一个循环,每次增加25%直到大于期望容量
Go1.18源码分析slice扩容规则
到了Go1.18时,又改成不和1024比较了,而是和256比较;并且扩容的增量也有所变化
newcap := old.cap doublecap := newcap + newcap if cap > doublecap { newcap = cap } else { const threshold = 256 if old.cap < threshold { newcap = doublecap } else { // Check 0 < newcap to detect overflow // and prevent an infinite loop. for 0 < newcap && newcap < cap { // 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 = cap } } }
什么是Map
最通俗的话说Map是一种通过key来获取value的一个数据结构,其底层存储方式为数组,在存储时key不能重复,当key重复时,value进行覆盖,我们通过key进行hash运算(可以简单理解为把key转化为一个整形数字)然后对数组的长度取余,得到key存储在数组的哪个下标位置,最后将key和value组装为一个结构体,放入数组下标处。
Go中Map的实现原理
知其然,知其所以然。map的源码位于 src/runtime/map.go中 ,map同样也是数组存储的的,每个数组下标处存储的是一个bucket,这个bucket的类型见下面代码,每个bucket中可以存储8个kv键值对,当每个bucket存储的kv对到达8个之后,会通过overflow指针指向一个新的bucket,从而形成一个链表,
底层数据结构体
创建map
写入map
读取流程
删除流程