教程集 www.jiaochengji.com
教程集 >  Golang编程  >  golang教程  >  正文 Golang 切片(slice)扩容机制源码剖析

Golang 切片(slice)扩容机制源码剖析

发布时间:2021-12-18   编辑:jiaochengji.com
教程集为您提供Golang 切片(slice)扩容机制源码剖析等资源,欢迎您收藏本站,我们将为您提供最新的Golang 切片(slice)扩容机制源码剖析资源

  目录

一、源码

二、原理

2.1 实例1

2.2 实例2

2.3 实例3


我们知道 Golang 切片(slice) 在容量不足的情况下会进行扩容,扩容的原理是怎样的呢?是不是每次扩一倍?下面我们结合源码来告诉你答案。

<h2 id="一、源码">一、源码</h2>

Version : go1.15.6  src/runtime/slice.go

<pre><code class="language-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 } } } //省略部分判断代码 } </code></pre> <h2 id="二、原理">二、原理</h2>

1. 如果当前所需容量 (cap) 大于原先容量的两倍 (doublecap),则最终申请容量(newcap)为当前所需容量(cap);

2. 如果<条件1>不满足,表示当前所需容量(cap)不大于原容量的两倍(doublecap),则进行如下判断;

3. 如果原切片长度(old.len)小于1024,则最终申请容量(newcap)等于原容量的两倍(doublecap);

4. 否则,最终申请容量(newcap,初始值等于 old.cap)每次增加 newcap/4,直到大于所需容量(cap)为止,然后,判断最终申请容量(newcap)是否溢出,如果溢出,最终申请容量(newcap)等于所需容量(cap);

这样说大家可能不太明白,来几个例子:

<h3 id="2.1 实例1">2.1 实例1</h3>

验证条件1:

<pre><code class="language-Go">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)) } </code></pre>

输出:

<pre><code class="language-Go">[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]#</code></pre>

在实例1中,所需容量 cap = 9 3 = 12,原容量的两倍 doublecap = 2 * 3 = 6,满足 <条件1> 即:所需容量大于原容量的两倍,所以最终申请容量 newcap = cap = 12。

<h3 id="2. 实例2">2.2 实例2</h3>

验证条件2,3:

<pre><code class="language-Go">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)) }</code></pre>

 输出:

<pre><code class="language-Go">[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]# </code></pre>

在实例2中,所需容量 cap = 7 2 = 9,原容量的两倍 doublecap = 2*7 = 14,原切片长度 old.len = 7,满足 <条件2,3>,即: 所需容量小于原容量的两倍,并且原切片长度 old.len 小于1024,所以,最终申请容量 newcap = doublecap = 14。

<h3 id="2.3 实例3">2.3 实例3</h3>

验证条件4:

<pre><code class="language-Go">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)) }</code></pre>

输出:

<pre><code class="language-Go">[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]#</code></pre>

在实例3中,所需容量 cap = 1024 2 = 1026,doublecap = 2048,  old.len = 1024,满足 <条件4> ,所以,newcap = 1024 1024/4 = 1280。

 

到此这篇关于“Golang 切片(slice)扩容机制源码剖析”的文章就介绍到这了,更多文章或继续浏览下面的相关文章,希望大家以后多多支持JQ教程网!

您可能感兴趣的文章:
Golang 切片(slice)扩容机制源码剖析
golang slice 最后一个元素_Go 常见的数据结构 Slice
Golang语言slice实现原理及使用方法
[go语言]-slice实现的使用和基本原理
切片 里面包含interface_Golang数据结构详解之切片
Go源码剖析:内置类型
Go range实现原理及性能优化剖析
深度解密Go语言之Slice
Golang 深入 slice 实现原理及使用技巧
【Go】深入剖析slice和array

[关闭]
~ ~