목차
용량이 부족하면 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>이 충족되지 않으면 현재 필요한 용량 (cap)이 원래 용량 (doublecap)의 2 배 이하임을 의미하며 다음과 같은 판단이 내려집니다.
3. 원래 슬라이스 길이 (old.len)가 1024보다 작 으면 최종 애플리케이션 용량 (newcap)은 원래 용량 (doublecap)의 두 배와 같습니다.
4. 그렇지 않을 경우 최종 적용 능력 (newcap, 초기 값은 old.cap과 같음)이 요구 용량 (cap) 이상이 될 때까지 매회 newcap / 4 씩 증가시킨 후 최종 적용 여부를 판단한다. 용량 (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에서 필요한 용량 한도 = 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입니다.