Golang 슬라이스 확장 메커니즘의 소스 코드 분석

  목차

하나, 소스 코드

2. 원리

2.1 예 1

2.2 예제 2

2.3 예제 3


용량이 부족하면 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입니다.

 

추천

출처blog.csdn.net/u011074149/article/details/111425091