【问题标题】:Confused about golang slice cap对golang切片帽感到困惑
【发布时间】:2021-09-16 03:36:13
【问题描述】:

我有一个关于切片帽的问题,代码:

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

如果项目 == 1:len(slice)=1,cap(slice)=1

如果项目 == 2:len(slice)=2,cap(slice)= 1*2

如果项目 ==3:len(slice) = 3,cap(slice) = 2*2

如果项目 == 4:len(slice) = 4,cap(slice) = 4

如果项目 == 5:len(slice) = 5,cap(slice) = 4*2

所以输出:

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

没问题,但是当我更改代码时:

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

输出:

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

为什么 cap(slice) = 6 ?

【问题讨论】:

  • 语言规范没有明确定义当 cap 不够大时追加算法应该做什么。因此,由 Go 运行时的实现者决定上限的增长方式。并且该实现可能会因版本而异。如果您想要了解该算法,那么您所要做的就是阅读源代码。如果您想要反对实施背后的基本原理,那么您可以尝试 go-nuts 邮件列表。作为一个反例尝试s := make([]int, 0, 4); fmt.Println(cap(append(s, 1,2,3,4,5)))

标签: go slice


【解决方案1】:

func growslice(et *_type, old slice, cap int)中追加src/runtime/slice.go时可以看到容量计算的算法——第162行

    newcap := old.cap
    doublecap := newcap + newcap
    if cap > doublecap {
        newcap = cap
    } else {
        if old.cap < 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。如果后面的容量 乘以 2 仍然小于新切片容量,则取 新切片容量(追加多个元素)
  • 如果新切片是 小于旧切片容量的两倍,乘以旧切片 容量增加 2
  • 如果旧分片容量大于等于1024,新分片容量 切片容量乘以旧切片容量乘以 1.25

参考-

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-09-13
    • 2012-07-22
    • 2013-05-13
    • 2020-04-16
    • 2023-03-08
    相关资源
    最近更新 更多