оглавление
Мы знаем, что сегменты Golang будут расширяться, когда мощности недостаточно. Каков принцип расширения? Он каждый раз удваивается? Ниже мы объединяем исходный код, чтобы дать вам ответ.
Один, исходный код
Версия: go1.15.6 src / runtime / slice.go
//go1.15.6 源码 src/runtime/slice.go
func growslice(et *_type, old slice, cap int) slice {
//省略部分判断代码
//计算扩容部分
//其中,cap : 所需容量,newcap : 最终申请容量
newcap := old.cap
doublecap := newcap + newcap
if cap > doublecap {
newcap = cap
} else {
if old.len < 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
}
}
}
//省略部分判断代码
}
2. Принцип
1. Если текущая требуемая емкость (cap) больше чем вдвое исходная емкость (doublecap), конечная емкость приложения (newcap) будет текущей требуемой емкостью (cap);
2. Если <условие 1> не выполняется, это означает, что текущая требуемая мощность (ограничение) не более чем в два раза превышает первоначальную вместимость (doublecap), тогда будут приняты следующие решения;
3. Если исходная длина фрагмента (old.len) меньше 1024, конечная емкость приложения (newcap) равна удвоенной исходной емкости (doublecap);
4. В противном случае конечная емкость приложения (newcap, начальное значение равно old.cap) увеличивается на newcap / 4 каждый раз до тех пор, пока она не станет больше требуемой емкости (cap), а затем проверяется, соответствует ли конечное приложение емкость (newcap) переполняется, если она переполняется, наконец, емкость приложения (newcap) равна требуемой емкости (cap);
Таким образом, вы можете не понять, вот несколько примеров:
2.1 Пример 1
Условие проверки 1:
package main
import "fmt"
func main() {
//第1条中的例子:
var slice = []int{1, 2, 3}
var slice1 = []int{4, 5, 6, 7, 8, 9, 10, 11, 12}
fmt.Printf("slice %v len = %v cap = %v\n", slice, len(slice), cap(slice))
fmt.Printf("slice1 %v len = %v cap = %v\n", slice1, len(slice1), cap(slice1))
slice = append(slice, slice1...)
fmt.Printf("slice %v len = %v cap = %v\n", slice, len(slice), cap(slice))
}
Вывод:
[root@localhost test]# go run main.go
slice [1 2 3] len = 3 cap = 3
slice1 [4 5 6 7 8 9 10 11 12] len = 9 cap = 9
slice [1 2 3 4 5 6 7 8 9 10 11 12] len = 12 cap = 12
[root@localhost test]#
В Примере 1 требуемый предел емкости = 9 + 3 = 12, doublecap = 2 * 3 = 6 раз больше исходной емкости и выполняется <условие 1>, то есть: требуемая емкость больше, чем в два раза исходной емкости, поэтому итоговая емкость приложения newcap = cap = 12.
2.2 Пример 2
Условия проверки 2,3:
package main
import "fmt"
func main() {
//第2、3条中的例子:
var slice = []int{1, 2, 3, 4, 5, 6, 7}
var slice1 = []int{8, 9}
fmt.Printf("slice %v len = %v cap = %v\n", slice, len(slice), cap(slice))
fmt.Printf("slice1 %v len = %v cap = %v\n", slice1, len(slice1), cap(slice1))
slice = append(slice, slice1...)
fmt.Printf("slice %v len = %v cap = %v\n", slice, len(slice), cap(slice))
}
Вывод:
[root@localhost test]# go run main.go
slice [1 2 3 4 5 6 7] len = 7 cap = 7
slice1 [8 9] len = 2 cap = 2
slice [1 2 3 4 5 6 7 8 9] len = 9 cap = 14
[root@localhost test]#
В Примере 2 требуемая емкость cap = 7 + 2 = 9, удвоенная исходная емкость doublecap = 2 * 7 = 14, исходная длина фрагмента old.len = 7, соответствует <условию 2, 3>, то есть: Требуется емкость меньше чем в два раза исходная емкость, а исходная длина фрагмента old.len меньше 1024, поэтому конечная емкость приложения newcap = doublecap = 14.
2.3 Пример 3
Условие проверки 4:
package main
import "fmt"
func main() {
//第2条中的例子:
var slice []int
for i := 0; i < 1024; i++ {
slice = append(slice, i)
}
var slice1 = []int{1024, 1025}
fmt.Printf("slice %v len = %v cap = %v\n", slice, len(slice), cap(slice))
fmt.Printf("slice1 %v len = %v cap = %v\n", slice1, len(slice1), cap(slice1))
slice = append(slice, slice1...)
fmt.Printf("slice %v len = %v cap = %v\n", slice, len(slice), cap(slice))
}
Вывод:
[root@localhost test]# go run main.go
slice [0 1 2 3 4 5 6……1017 1018 1019 1020 1021 1022 1023] len = 1024 cap = 1024
slice1 [1024 1025] len = 2 cap = 2
slice [0 1 2 3 4 5 6……1017 1018 1019 1020 1021 1022 1023 1024 1025] len = 1026 cap = 1280
[root@localhost test]#
В примере 3 необходимое ограничение емкости = 1024 + 2 = 1026, doublecap = 2048, old.len = 1024 и <условие 4> выполнено, поэтому newcap = 1024 + 1024/4 = 1280.