内容概要
- 数组(
Array
) - 切片(
Slice
) -
string
&[]byte
-
map
实现原理 -
sync.Map
实现原理 -
go
的continer
包
1、数组(Array)
数组定义:固定长度、特定类型组成的序列。
内存结构:[4]int{2,3,5,7}
数组内存结构
数组缺点:
- 不同长度的数组是不同的类型,无法直接赋值
- 长度固定,使用不便
- 作为参数传递表现为传值
2、切片(Slice)
切片
package main
import "fmt"
func main() {
array := [10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
s := array[2:3]
fmt.Println(len(s))
fmt.Println(cap(s))
fmt.Println(s)
fmt.Println(&array[2] == &s[0])
}
编译结果:
1
8
[3]
true
package main
import "fmt"
func main() {
sliceA := []int{1, 2, 3}
editElem(sliceA)
fmt.Println(sliceA)
}
func editElem(sliceTmp []int) {
sliceTmp[1] = 999
}
编译结果:
[1 999 3]
append 扩容规则:
- if cap < 1024, cap * 2
- else, cap * 1.25
package main
import "fmt"
func main() {
slice := []int{1}
fmt.Println(len(slice), cap(slice))
slice = append(slice, 1)
fmt.Println(len(slice), cap(slice))
slice = append(slice, 1)
fmt.Println(len(slice), cap(slice))
slice = append(slice, 1)
fmt.Println(len(slice), cap(slice))
slice = append(slice, 1)
fmt.Println(len(slice), cap(slice))
}
编译结果:
1 1
2 2
3 4
4 4
5 8
package main
import "fmt"
func main() {
sliceA := make([]int, 4, 5)
sliceB := addElem(sliceA)
fmt.Println(sliceA)
fmt.Println(sliceB)
fmt.Println(&sliceA[0] == &sliceB[0])
sliceC := make([]int, 5, 5)
sliceD := addElem(sliceA)
fmt.Println(sliceC)
fmt.Println(sliceD)
fmt.Println(&sliceC[0] == &sliceD[0])
}
func addElem(tmpSlice []int) []int {
return append(tmpSlice, 1)
}
编译结果:
[0 0 0 0]
[0 0 0 0 1]
true
[0 0 0 0 0]
[0 0 0 0 1]
false
package main
import "fmt"
func main() {
sliceA := make([]int, 0, 5)
addElem(sliceA)
fmt.Println(sliceA)
}
func addElem(sliceTmp []int) {
sliceTmp = append(sliceTmp, 999)
}
编译结果:
[]
切片
3、string & []byte
string 对象不可以修改
- 不包含内存空间:避免内存拷贝
-
字符串字面量在只读段上分配,无法修改
数据结构
package main
import "fmt"
func main() {
a := "abcdefg"
a = "qwertyuiop"
fmt.Println(a)
}
编译结果:
qwertyuiop
string / []byte 强转
package main
import "fmt"
func main() {
a := "qwertyuiop"
bytes := []byte(a)
bytes[4] = '6'
fmt.Println(string(bytes))
}
编译结果:
qwer6yuiop
string / []byte 强转
4、map 实现原理
map 结构由 runtime/map.go/hmap 定义
image.png
hash 冲突导致bucket溢出
image.png
负载因子 = 键数量 / bucket 数量
rehash:
- 负载因子 > 6.5 (增量扩容)
- overflow 数量过多 (等量扩容)
增量扩容
image.png
等量扩容
image.png
同一个map连续两次遍历为什么顺序不同?
- 表面原因:原生遍历map的函数中插入了随机数,导致无序
- 深层原因:rehash,避免初学者依赖这个遍历结果的顺序
map 并发读写会panic
- 通过 sync.RWMutex 加读写锁
- 使用 并发安全的 sync.Map
5、sync.Map 实现原理
image.png
sync/map.go
读写分离,提高并发度
sync.Map 适用场景:读多写少
image.png
6、go 的 continer 包
continer/heap : 小根堆
continer/list : 双向链表
continer/ring : 双向环