源代码

runtime/slice.go

1
2
3
4
5
type slice struct {
array unsafe.Pointer
len int
cap int
}

2行 指向底层数组的指针

3行 长度大小

4行 容量大小

go-38-001

字面量创建切片

1
2
3
4
5
6
7
8
package main

import "fmt"

func main() {
s := []string{"碳烤生蚝", "红烧肉", "帝王蟹"}
fmt.Println(s)
}

go build -gcflags -S main.go

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
 ...
0x0018 00024 (/menu7/main.go:6) MOVD $type.[3]string(SB), R0
0x0020 00032 (/menu7/main.go:6) PCDATA $1, ZR
0x0020 00032 (/menu7/main.go:6) CALL runtime.newobject(SB)
0x0024 00036 (/menu7/main.go:6) MOVD $12, R1
0x0028 00040 (/menu7/main.go:6) MOVD R1, 8(R0)
0x002c 00044 (/menu7/main.go:6) MOVD $go.string."碳烤生蚝"(SB), R1
0x0034 00052 (/menu7/main.go:6) MOVD R1, (R0)
0x0038 00056 (/menu7/main.go:6) MOVD $9, R1
0x003c 00060 (/menu7/main.go:6) MOVD R1, 24(R0)
0x0040 00064 (/menu7/main.go:6) MOVD $go.string."红烧肉"(SB), R2
0x0048 00072 (/menu7/main.go:6) MOVD R2, 16(R0)
0x004c 00076 (/menu7/main.go:6) MOVD R1, 40(R0)
0x0050 00080 (/menu7/main.go:6) MOVD $go.string."帝王蟹"(SB), R1
0x0058 00088 (/menu7/main.go:6) MOVD R1, 32(R0)
...

2行 创建3个string大小的数组

4行 创建slice结构体

make函数创建切片

1
2
s2 := make([]string, 5)
fmt.Println(s2)

runtime/slice.go

1
2
3
func makeslice(et *_type, len, cap int) unsafe.Pointer {
...
}

切片扩容

可以容纳新元素

go-38-002

可以看到上图,还有一个空位置,那么再来一个元素是可以放进去的,没有问题。

新增元素多余剩余空间

go-38-003

可以看到上图,原本的数组不够放入新元素,那么就会新找一个连续的位置,存放新的数组,并且把原来数组内容复制过去,再新增内容。

切片长度<1024,扩容的容量会翻倍

切片长度>1024,扩容的容量增加25%

切片扩容的时候,并发不安全,有必要考虑加锁

runtime/slice.go

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
func growslice(et *_type, old slice, cap int) slice {
...
newcap := old.cap
doublecap := newcap + newcap
if cap > doublecap {
newcap = cap
} else {
const threshold = 256
if old.cap < threshold {
newcap = doublecap
} else {
for 0 < newcap && newcap < cap {
newcap += (newcap + 3*threshold) / 4
}
if newcap <= 0 {
newcap = cap
}
}
}
...
}

如何学习Go语言微服务,快速步入架构师

从0到Go语言微服务架构师-海报 从0到Go语言微服务架构师
添加微信 公众号更多内容
wechat gzh