slice
切片本身并不是动态数组或者数组指针。它内部实现的数据结构通过指针引用底层数组,设定相关属性将数据读写操作限定在指定的区域内。切片本身是一个只读对象,其工作机制类似数组指针的一种封装
- 底层结构:array指针、长度、容量
- 与 array 的区别
- array 需要指定长度,且不可改变
- Golang 所有的参数传递都是值传递
- append 三种方式对比
- 初始化时不指定长度、容量,直接 append 最慢,造成多次扩容;
- 初始化时指定容量,不指定长度时 append 较快。适用于长度不确定但最大长度确定的情况;
- 初始化时指定长度和容量,利用 index 赋值最快。适用于长度确定的情况。
- 函数参数的传递是值传递
- 切片的 array 字段存的是指针。如果没有发生扩容,修改在原来的内存中
- 如果发生了扩容,修改会在新的内存中
slice扩容策略
slice扩容策略
###slice扩容策略
slice扩容策略:
首先判断,如果新申请容量(cap)大于2倍的旧容量(old.cap),最终容量(newcap)就是新申请的容量(cap)
否则判断,如果旧切片的长度小于1024,则最终容量(newcap)就是旧容量(old.cap)的两倍,即(newcap=doublecap)
否则判断,如果旧切片长度大于等于1024,则最终容量(newcap)从旧容量(old.cap)开始循环增加原来的 1/4(1.25倍),即(newcap=old.cap,for {newcap += newcap/4})直到最终容量(newcap)大于等于新申请的容量(cap),即(newcap >= cap)
如果最终容量(cap)计算值溢出,则最终容量(cap)就是新申请容量(cap)
- 使用 []Type{} 或 make([]Type) 初始化后,slice 不为 nil
- 使用 var s []Type 后,slice 为 nil
Map
- 实现是拉链法
- map 实际上的值是个指针,传递的是指针
- 修改会影响整个 map
- map 的 key 和 value 都无法取地址,因为随着扩容地址会改变
- map 存的是值,会发生 copy
- map 删除 key 不会自动缩容
Channel
- channel 是有锁的
- channel 调用会触发调度
- 高并发、高性能编程不适合使用 channel(锁降低了性能)
- buffered channel 会发生两次 copy:
- send goroutine -> buf
- buf -> receive goroutine
- unbuffered channel 会发生一次 copy:
- send goroutine -> receive goroutine
- unbuffered channel,receive 完成后 send 才会返回(阻塞发送)
- for + select closed channel 会造成死循环,会给channel类型的0值
- break 无法跳出 for,只能跳出 select