func main() { print("1","2","3")}func print (a ...interface{}){ for _,v:=range a{fmt.Print(v) } fmt.Println()}
例子中我们自己定义了一个接受可变参数的函数,效果和fmt.Println()一样 。可变参数本质上是一个数组,所以我们向使用数组一样使用它,比如例子中的 for range 循环 。
42.Golang Slice的底层实现切片是基于数组实现的,它的底层是数组,它自己本身非常小,可以理解为对底层数组的抽象 。因为基于数组实现,所以它的底层的内存是连续分配的,效率非常高,还可以通过索引获得数据,可以迭代以及垃圾回收优化 。切片本身并不是动态数组或者数组指针 。它内部实现的数据结构通过指针引用底层数组,设定相关属性将数据读写操作限定在指定的区域内 。切片本身是一个只读对象,其工作机制类似数组指针的一种封装 。切片对象非常小,是因为它是只有3个字段的数据结构:
- 指向底层数组的指针
- 切片的长度
- 切片的容量

文章插图
43.Golang Slice的扩容机制,有什么注意点Go 中切片扩容的策略是这样的:
首先判断,如果新申请容量大于 2 倍的旧容量,最终容量就是新申请的容量 。否则判断,如果旧切片的长度小于 1024,则最终容量就是旧容量的两倍 。
否则判断,如果旧切片长度大于等于 1024,则最终容量从旧容量开始循环增加原来的 1/4 , 直到最终容量大于等于新申请的容量 。如果最终容量计算值溢出,则最终容量就是新申请容量 。
- 情况一:原数组还有容量可以扩容(实际容量没有填充完),这种情况下,扩容以后的数组还是指向原来的数组,对一个切片的操作可能影响多个指针指向相同地址的Slice 。
- 情况二:原来数组的容量已经达到了最大值,再想扩容, Go 默认会先开一片内存区域,把原来的值拷贝过来,然后再执行 append() 操作 。这种情况丝毫不影响原数组 。
44.Golang Map底层实现Golang 中 map 的底层实现是一个散列表,因此实现 map 的过程实际上就是实现散表的过程 。在这个散列表中,主要出现的结构体有两个,一个叫hmap(a header for a go map),一个叫bmap(a bucket for a Go map,通常叫其bucket) 。
hmap如下所示:

文章插图
图中有很多字段,但是便于理解 map 的架构,你只需要关心的只有一个,就是标红的字段:buckets 数组 。Golang 的 map 中用于存储的结构是 bucket数组 。而 bucket(即bmap)的结构是怎样的呢?bucket:

文章插图
相比于 hmap,bucket 的结构显得简单一些,标橙的字段依然是“核心”,我们使用的 map 中的 key 和 value 就存储在这里 。
“高位哈希值”数组记录的是当前 bucket 中 key 相关的”索引”,稍后会详细叙述 。还有一个字段是一个指向扩容后的 bucket 的指针,使得 bucket 会形成一个链表结构 。整体的结构应该是这样的:

文章插图
Golang 把求得的哈希值按照用途一分为二:高位和低位 。低位用于寻找当前 key属于 hmap 中的哪个 bucket,而高位用于寻找 bucket 中的哪个 key 。需要特别指出的一点是:map中的key/value值都是存到同一个数组中的 。这样做的好处是:在key和value的长度不同的时候,可以消除padding带来的空间浪费 。
经验总结扩展阅读
- 早晨问好的励志优美句子 早安最短精句早上好
- 惠普星13air缺点_惠普星13air有哪些问题
- C# 8.0 添加和增强的功能【基础篇】
- 下午最美祝福语 最新下午好问候语温馨短句
- 下午问候语温馨一句话 愉快的下午说说心情
- 下午发朋友圈的说说心情 下午好温馨问候语
- 适合下午发的心情说说 高情商下午好问候
- 下午好问候语简短句子 下午心情短句
- 下午好简短祝福语 高情商下午好问候简短句子
- 下午的问候语温馨的话 下午好正能量短句