对于 golang 中的切片(slice)的 cap 属性感到困惑。

huangapple go评论77阅读模式
英文:

Confused about golang slice cap

问题

我对切片容量的问题有疑问,以下是代码:

var slice []int
list := []int{1,2,3,4,5}
for _,item := range list {
    slice = append(slice, item)
}
fmt.Println(len(slice),cap(slice))

如果 item == 1len(slice)=1cap(slice)=1

如果 item == 2len(slice)=2cap(slice)=1*2

如果 item == 3len(slice)=3cap(slice)=2*2

如果 item == 4len(slice)=4cap(slice)=4

如果 item == 5len(slice)=5cap(slice)=4*2

所以输出结果为:

len(slice)=5cap(slice)=8

这没有问题,但当我改变代码如下:

var slice []int
slice = append(slice,1,2,3,4,5)
fmt.Println(len(slice),cap(slice))

输出结果为:

len(slice)=5cap(slice)=6

为什么 cap(slice)=6

英文:

i have a question about slice cap,the code:

var slice []int
list := []int{1,2,3,4,5}
for _,item := range list {
	slice = append(slice, item)
}
fmt.Println(len(slice),cap(slice))

if item == 1: len(slice)=1,cap(slice)=1

if item == 2: len(slice)=2,cap(slice)= 1*2

if item ==3: len(slice) = 3,cap(slice) = 2*2

if item == 4:len(slice) = 4,cap(slice) = 4

if item == 5:len(slice) = 5,cap(slice) = 4*2

so the output:

len(slice) = 5,cap(slice) = 8

that's no problem,but when i change the code:

var slice []int
slice = append(slice,1,2,3,4,5)
fmt.Println(len(slice),cap(slice))

output:

len(slice) = 5,cap(slice) = 6

why cap(slice) = 6 ?

答案1

得分: 6

你可以在src/runtime/slice.gofunc growslice(et *_type, old slice, cap int)函数中看到在追加时进行容量计算的算法-第162行。

    newcap := old.cap
	doublecap := newcap + newcap
	if cap > doublecap {
		newcap = cap
	} else {
		if old.cap < 1024 {
			newcap = doublecap
		} else {
			// 检查 0 < newcap 以检测溢出并防止无限循环。
			for 0 < newcap && newcap < cap {
				newcap += newcap / 4
			}
			// 当新容量计算溢出时,将newcap设置为请求的容量。
			if newcap <= 0 {
				newcap = cap
			}
		}
	}

> - 首先将旧切片的容量乘以2。如果乘以2后的容量仍然小于新切片的容量,则取新切片的容量(追加多个元素)。
> - 如果新切片小于旧切片容量的两倍,则将旧切片的容量乘以2。
> - 如果旧切片的容量大于或等于1024,则将新切片的容量乘以旧切片容量的1.25倍。

参考资料:

英文:

You can see the algorithm of capacity calculation when appending in func growslice(et *_type, old slice, cap int) in src/runtime/slice.go - line 162

    newcap := old.cap
	doublecap := newcap + newcap
	if cap &gt; doublecap {
		newcap = cap
	} else {
		if old.cap &lt; 1024 {
			newcap = doublecap
		} else {
			// Check 0 &lt; newcap to detect overflow
			// and prevent an infinite loop.
			for 0 &lt; newcap &amp;&amp; newcap &lt; cap {
				newcap += newcap / 4
			}
			// Set newcap to the requested cap when
			// the newcap calculation overflowed.
			if newcap &lt;= 0 {
				newcap = cap
			}
		}
	}

> - First multiply the old slice capacity by 2. If the capacity after
> multiplying by 2 is still less than the new slice capacity, then take
> the new slice capacity (append multiple elems)
> - If the new slice is
> less than twice the old slice capacity, multiply the old slice
> capacity by 2
> - If the old slice capacity is greater than or equal to 1024, the new
> slice capacity is multiplied by the old slice capacity by 1.25

Reference -

huangapple
  • 本文由 发表于 2021年7月5日 18:38:14
  • 转载请务必保留本文链接:https://go.coder-hub.com/68254699.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定