教程集 www.jiaochengji.com
教程集 >  Golang编程  >  golang教程  >  正文 Slice实现原理分析

Slice实现原理分析

发布时间:2021-12-25   编辑:jiaochengji.com
教程集为您提供Slice实现原理分析等资源,欢迎您收藏本站,我们将为您提供最新的Slice实现原理分析资源
<svg xmlns="http://www.w3.org/2000/svg" style="display: none;"><path stroke-linecap="round" d="M5,0 0,2.5 5,5z" id="raphael-marker-block" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);"/></svg>

众所周知,在golang中,slice(切片)是我们最常使用到的一种数据结构,是一种可变长度的数组,本篇文章我们主要结合源码来介绍一下slice的底层实现,以及在使用slice时的一些注意事项。

<h3>文章目录</h3> <ul><li>slice结构体</li><li>slice初始化</li><li>append操作</li><li>slice截取</li><li>slice深拷贝</li><li>值传递还是引用传递</li><li>参考文献</li></ul>

<h1>slice结构体</h1>

首先我们来看一段代码:

<pre><code class="lang-go hljs"> <span class="token keyword">package</span> main <span class="token keyword">import</span> <span class="token punctuation">(</span> <span class="token string">"fmt"</span> <span class="token string">"unsafe"</span> <span class="token punctuation">)</span> <span class="token keyword">func</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">var</span> a <span class="token builtin">int</span> <span class="token keyword">var</span> b <span class="token builtin">int8</span> <span class="token keyword">var</span> c <span class="token builtin">int16</span> <span class="token keyword">var</span> d <span class="token builtin">int32</span> <span class="token keyword">var</span> e <span class="token builtin">int64</span> slice <span class="token operator">:=</span> <span class="token function">make</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token builtin">int</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">)</span> slice <span class="token operator">=</span> <span class="token function">append</span><span class="token punctuation">(</span>slice<span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">)</span> fmt<span class="token punctuation">.</span><span class="token function">Printf</span><span class="token punctuation">(</span><span class="token string">"int:%d\nint8:%d\nint16:%d\nint32:%d\nint64:%d\n"</span><span class="token punctuation">,</span> unsafe<span class="token punctuation">.</span><span class="token function">Sizeof</span><span class="token punctuation">(</span>a<span class="token punctuation">)</span><span class="token punctuation">,</span> unsafe<span class="token punctuation">.</span><span class="token function">Sizeof</span><span class="token punctuation">(</span>b<span class="token punctuation">)</span><span class="token punctuation">,</span> unsafe<span class="token punctuation">.</span><span class="token function">Sizeof</span><span class="token punctuation">(</span>c<span class="token punctuation">)</span><span class="token punctuation">,</span> unsafe<span class="token punctuation">.</span><span class="token function">Sizeof</span><span class="token punctuation">(</span>d<span class="token punctuation">)</span><span class="token punctuation">,</span> unsafe<span class="token punctuation">.</span><span class="token function">Sizeof</span><span class="token punctuation">(</span>e<span class="token punctuation">)</span><span class="token punctuation">)</span> fmt<span class="token punctuation">.</span><span class="token function">Printf</span><span class="token punctuation">(</span><span class="token string">"slice:%d"</span><span class="token punctuation">,</span> unsafe<span class="token punctuation">.</span><span class="token function">Sizeof</span><span class="token punctuation">(</span>slice<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> </code></pre>

该程序输出golang中常用数据类型占多少byte,输出结果是:

<pre><code class="lang-go hljs"><span class="token builtin">int</span><span class="token punctuation">:</span><span class="token number">8</span> <span class="token builtin">int8</span><span class="token punctuation">:</span><span class="token number">1</span> <span class="token builtin">int16</span><span class="token punctuation">:</span><span class="token number">2</span> <span class="token builtin">int32</span><span class="token punctuation">:</span><span class="token number">4</span> <span class="token builtin">int64</span><span class="token punctuation">:</span><span class="token number">8</span> slice<span class="token punctuation">:</span><span class="token number">24</span> </code></pre>

我们可以看到slice占24byte,为什么会占24byte,这就跟slice底层定义的结构有关,我们在golang的runtime/slice.go中可以找到slice的结构定义,如下:

<pre><code class="lang-go hljs"><span class="token keyword">type</span> slice <span class="token keyword">struct</span> <span class="token punctuation">{</span> array unsafe<span class="token punctuation">.</span>Pointer<span class="token comment">//指向底层数组的指针</span> <span class="token builtin">len</span> <span class="token builtin">int</span><span class="token comment">//切片的长度</span> <span class="token builtin">cap</span> <span class="token builtin">int</span><span class="token comment">//切片的容量</span> <span class="token punctuation">}</span> </code></pre>

我们可以看到slice中定义了三个变量,一个是指向底层数字的指针array,另外两个是切片的长度len和切片的容量cap。

<h1>
slice初始化</h1>

简单了解了slice的底层结构后,我们来看下slice的初始化,在golang中slice有多重初始化方式,在这里我们就不一一介绍了,我们主要关注slice在底层是如何初始化的,首先我们来看一段代码:

<pre><code class="lang-go hljs"><span class="token keyword">package</span> main <span class="token keyword">import</span> <span class="token string">"fmt"</span> <span class="token keyword">func</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> slice <span class="token operator">:=</span> <span class="token function">make</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token builtin">int</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">)</span> slice <span class="token operator">=</span> <span class="token function">append</span><span class="token punctuation">(</span>slice<span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">)</span> fmt<span class="token punctuation">.</span><span class="token function">Println</span><span class="token punctuation">(</span>slice<span class="token punctuation">,</span> <span class="token function">len</span><span class="token punctuation">(</span>slice<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token function">cap</span><span class="token punctuation">(</span>slice<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> </code></pre>

很简单的一段代码,make一个slice,往slice中append一个一个1,打印slice内容,长度和容量,接下来我们利用gotool提供的工具将以上代码反汇编:

<pre><code class="lang-go hljs"><span class="token keyword">go</span> tool compile <span class="token operator">-</span>S slice<span class="token punctuation">.</span><span class="token keyword">go</span> </code></pre>

得到汇编代码如下(截取部分):

<pre><code class="lang-go hljs"><span class="token number">0x0000</span> <span class="token number">00000</span> <span class="token punctuation">(</span>slice<span class="token punctuation">.</span><span class="token keyword">go</span><span class="token punctuation">:</span><span class="token number">8</span><span class="token punctuation">)</span> TEXT <span class="token string">""</span><span class="token punctuation">.</span><span class="token function">main</span><span class="token punctuation">(</span>SB<span class="token punctuation">)</span><span class="token punctuation">,</span> ABIInternal<span class="token punctuation">,</span> $<span class="token number">152</span><span class="token operator">-</span><span class="token number">0</span> <span class="token number">0x0000</span> <span class="token number">00000</span> <span class="token punctuation">(</span>slice<span class="token punctuation">.</span><span class="token keyword">go</span><span class="token punctuation">:</span><span class="token number">8</span><span class="token punctuation">)</span> MOVQ <span class="token punctuation">(</span>TLS<span class="token punctuation">)</span><span class="token punctuation">,</span> CX <span class="token number">0x0009</span> <span class="token number">00009</span> <span class="token punctuation">(</span>slice<span class="token punctuation">.</span><span class="token keyword">go</span><span class="token punctuation">:</span><span class="token number">8</span><span class="token punctuation">)</span> LEAQ <span class="token operator">-</span><span class="token function">24</span><span class="token punctuation">(</span>SP<span class="token punctuation">)</span><span class="token punctuation">,</span> AX <span class="token number">0x000e</span> <span class="token number">00014</span> <span class="token punctuation">(</span>slice<span class="token punctuation">.</span><span class="token keyword">go</span><span class="token punctuation">:</span><span class="token number">8</span><span class="token punctuation">)</span> CMPQ AX<span class="token punctuation">,</span> <span class="token function">16</span><span class="token punctuation">(</span>CX<span class="token punctuation">)</span> <span class="token number">0x0012</span> <span class="token number">00018</span> <span class="token punctuation">(</span>slice<span class="token punctuation">.</span><span class="token keyword">go</span><span class="token punctuation">:</span><span class="token number">8</span><span class="token punctuation">)</span> JLS <span class="token number">375</span> <span class="token number">0x0018</span> <span class="token number">00024</span> <span class="token punctuation">(</span>slice<span class="token punctuation">.</span><span class="token keyword">go</span><span class="token punctuation">:</span><span class="token number">8</span><span class="token punctuation">)</span> SUBQ $<span class="token number">152</span><span class="token punctuation">,</span> SP <span class="token number">0x001f</span> <span class="token number">00031</span> <span class="token punctuation">(</span>slice<span class="token punctuation">.</span><span class="token keyword">go</span><span class="token punctuation">:</span><span class="token number">8</span><span class="token punctuation">)</span> MOVQ BP<span class="token punctuation">,</span> <span class="token function">144</span><span class="token punctuation">(</span>SP<span class="token punctuation">)</span> <span class="token number">0x0027</span> <span class="token number">00039</span> <span class="token punctuation">(</span>slice<span class="token punctuation">.</span><span class="token keyword">go</span><span class="token punctuation">:</span><span class="token number">8</span><span class="token punctuation">)</span> LEAQ <span class="token function">144</span><span class="token punctuation">(</span>SP<span class="token punctuation">)</span><span class="token punctuation">,</span> BP <span class="token number">0x002f</span> <span class="token number">00047</span> <span class="token punctuation">(</span>slice<span class="token punctuation">.</span><span class="token keyword">go</span><span class="token punctuation">:</span><span class="token number">8</span><span class="token punctuation">)</span> FUNCDATA $<span class="token number">0</span><span class="token punctuation">,</span> gclocals<span class="token operator">-</span> <span class="token function">f14a5bc6d08bc46424827f54d2e3f8ed</span><span class="token punctuation">(</span>SB<span class="token punctuation">)</span><span class="token comment">//编译器产生,用于保存一些垃圾收集相关的信息</span> <span class="token number">0x002f</span> <span class="token number">00047</span> <span class="token punctuation">(</span>slice<span class="token punctuation">.</span><span class="token keyword">go</span><span class="token punctuation">:</span><span class="token number">8</span><span class="token punctuation">)</span> FUNCDATA $<span class="token number">1</span><span class="token punctuation">,</span> gclocals<span class="token operator">-</span> <span class="token function">3e7bd269c75edba02eda3b9069a96409</span><span class="token punctuation">(</span>SB<span class="token punctuation">)</span> <span class="token number">0x002f</span> <span class="token number">00047</span> <span class="token punctuation">(</span>slice<span class="token punctuation">.</span><span class="token keyword">go</span><span class="token punctuation">:</span><span class="token number">8</span><span class="token punctuation">)</span> FUNCDATA $<span class="token number">2</span><span class="token punctuation">,</span> gclocals<span class="token operator">-</span> <span class="token function">f6aec3988379d2bd21c69c093370a150</span><span class="token punctuation">(</span>SB<span class="token punctuation">)</span> <span class="token number">0x002f</span> <span class="token number">00047</span> <span class="token punctuation">(</span>slice<span class="token punctuation">.</span><span class="token keyword">go</span><span class="token punctuation">:</span><span class="token number">8</span><span class="token punctuation">)</span> FUNCDATA $<span class="token number">3</span><span class="token punctuation">,</span> <span class="token string">""</span><span class="token punctuation">.</span>main<span class="token punctuation">.</span><span class="token function">stkobj</span><span class="token punctuation">(</span>SB<span class="token punctuation">)</span> <span class="token number">0x002f</span> <span class="token number">00047</span> <span class="token punctuation">(</span>slice<span class="token punctuation">.</span><span class="token keyword">go</span><span class="token punctuation">:</span><span class="token number">9</span><span class="token punctuation">)</span> PCDATA $<span class="token number">0</span><span class="token punctuation">,</span> $<span class="token number">1</span> <span class="token number">0x002f</span> <span class="token number">00047</span> <span class="token punctuation">(</span>slice<span class="token punctuation">.</span><span class="token keyword">go</span><span class="token punctuation">:</span><span class="token number">9</span><span class="token punctuation">)</span> PCDATA $<span class="token number">1</span><span class="token punctuation">,</span> $<span class="token number">0</span> <span class="token number">0x002f</span> <span class="token number">00047</span> <span class="token punctuation">(</span>slice<span class="token punctuation">.</span><span class="token keyword">go</span><span class="token punctuation">:</span><span class="token number">9</span><span class="token punctuation">)</span> LEAQ <span class="token keyword">type</span><span class="token punctuation">.</span><span class="token function">int</span><span class="token punctuation">(</span>SB<span class="token punctuation">)</span><span class="token punctuation">,</span> AX <span class="token number">0x0036</span> <span class="token number">00054</span> <span class="token punctuation">(</span>slice<span class="token punctuation">.</span><span class="token keyword">go</span><span class="token punctuation">:</span><span class="token number">9</span><span class="token punctuation">)</span> PCDATA $<span class="token number">0</span><span class="token punctuation">,</span> $<span class="token number">0</span> <span class="token number">0x0036</span> <span class="token number">00054</span> <span class="token punctuation">(</span>slice<span class="token punctuation">.</span><span class="token keyword">go</span><span class="token punctuation">:</span><span class="token number">9</span><span class="token punctuation">)</span> MOVQ AX<span class="token punctuation">,</span> <span class="token punctuation">(</span>SP<span class="token punctuation">)</span> <span class="token number">0x003a</span> <span class="token number">00058</span> <span class="token punctuation">(</span>slice<span class="token punctuation">.</span><span class="token keyword">go</span><span class="token punctuation">:</span><span class="token number">9</span><span class="token punctuation">)</span> XORPS X0<span class="token punctuation">,</span> X0 <span class="token number">0x003d</span> <span class="token number">00061</span> <span class="token punctuation">(</span>slice<span class="token punctuation">.</span><span class="token keyword">go</span><span class="token punctuation">:</span><span class="token number">9</span><span class="token punctuation">)</span> MOVUPS X0<span class="token punctuation">,</span> <span class="token function">8</span><span class="token punctuation">(</span>SP<span class="token punctuation">)</span> <span class="token number">0x0042</span> <span class="token number">00066</span> <span class="token punctuation">(</span>slice<span class="token punctuation">.</span><span class="token keyword">go</span><span class="token punctuation">:</span><span class="token number">9</span><span class="token punctuation">)</span> CALL runtime<span class="token punctuation">.</span><span class="token function">makeslice</span><span class="token punctuation">(</span>SB<span class="token punctuation">)</span><span class="token comment">//初始化slice</span> <span class="token number">0x0047</span> <span class="token number">00071</span> <span class="token punctuation">(</span>slice<span class="token punctuation">.</span><span class="token keyword">go</span><span class="token punctuation">:</span><span class="token number">9</span><span class="token punctuation">)</span> PCDATA $<span class="token number">0</span><span class="token punctuation">,</span> $<span class="token number">1</span> <span class="token number">0x0047</span> <span class="token number">00071</span> <span class="token punctuation">(</span>slice<span class="token punctuation">.</span><span class="token keyword">go</span><span class="token punctuation">:</span><span class="token number">9</span><span class="token punctuation">)</span> MOVQ <span class="token function">24</span><span class="token punctuation">(</span>SP<span class="token punctuation">)</span><span class="token punctuation">,</span> AX <span class="token number">0x004c</span> <span class="token number">00076</span> <span class="token punctuation">(</span>slice<span class="token punctuation">.</span><span class="token keyword">go</span><span class="token punctuation">:</span><span class="token number">10</span><span class="token punctuation">)</span> PCDATA $<span class="token number">0</span><span class="token punctuation">,</span> $<span class="token number">2</span> <span class="token number">0x004c</span> <span class="token number">00076</span> <span class="token punctuation">(</span>slice<span class="token punctuation">.</span><span class="token keyword">go</span><span class="token punctuation">:</span><span class="token number">10</span><span class="token punctuation">)</span> LEAQ <span class="token keyword">type</span><span class="token punctuation">.</span><span class="token function">int</span><span class="token punctuation">(</span>SB<span class="token punctuation">)</span><span class="token punctuation">,</span> CX <span class="token number">0x0053</span> <span class="token number">00083</span> <span class="token punctuation">(</span>slice<span class="token punctuation">.</span><span class="token keyword">go</span><span class="token punctuation">:</span><span class="token number">10</span><span class="token punctuation">)</span> PCDATA $<span class="token number">0</span><span class="token punctuation">,</span> $<span class="token number">1</span> <span class="token number">0x0053</span> <span class="token number">00083</span> <span class="token punctuation">(</span>slice<span class="token punctuation">.</span><span class="token keyword">go</span><span class="token punctuation">:</span><span class="token number">10</span><span class="token punctuation">)</span> MOVQ CX<span class="token punctuation">,</span> <span class="token punctuation">(</span>SP<span class="token punctuation">)</span> <span class="token number">0x0057</span> <span class="token number">00087</span> <span class="token punctuation">(</span>slice<span class="token punctuation">.</span><span class="token keyword">go</span><span class="token punctuation">:</span><span class="token number">10</span><span class="token punctuation">)</span> PCDATA $<span class="token number">0</span><span class="token punctuation">,</span> $<span class="token number">0</span> <span class="token number">0x0057</span> <span class="token number">00087</span> <span class="token punctuation">(</span>slice<span class="token punctuation">.</span><span class="token keyword">go</span><span class="token punctuation">:</span><span class="token number">10</span><span class="token punctuation">)</span> MOVQ AX<span class="token punctuation">,</span> <span class="token function">8</span><span class="token punctuation">(</span>SP<span class="token punctuation">)</span> <span class="token number">0x005c</span> <span class="token number">00092</span> <span class="token punctuation">(</span>slice<span class="token punctuation">.</span><span class="token keyword">go</span><span class="token punctuation">:</span><span class="token number">10</span><span class="token punctuation">)</span> XORPS X0<span class="token punctuation">,</span> X0 <span class="token number">0x005f</span> <span class="token number">00095</span> <span class="token punctuation">(</span>slice<span class="token punctuation">.</span><span class="token keyword">go</span><span class="token punctuation">:</span><span class="token number">10</span><span class="token punctuation">)</span> MOVUPS X0<span class="token punctuation">,</span> <span class="token function">16</span><span class="token punctuation">(</span>SP<span class="token punctuation">)</span> <span class="token number">0x0064</span> <span class="token number">00100</span> <span class="token punctuation">(</span>slice<span class="token punctuation">.</span><span class="token keyword">go</span><span class="token punctuation">:</span><span class="token number">10</span><span class="token punctuation">)</span> MOVQ $<span class="token number">1</span><span class="token punctuation">,</span> <span class="token function">32</span><span class="token punctuation">(</span>SP<span class="token punctuation">)</span> <span class="token number">0x006d</span> <span class="token number">00109</span> <span class="token punctuation">(</span>slice<span class="token punctuation">.</span><span class="token keyword">go</span><span class="token punctuation">:</span><span class="token number">10</span><span class="token punctuation">)</span> CALL runtime<span class="token punctuation">.</span><span class="token function">growslice</span><span class="token punctuation">(</span>SB<span class="token punctuation">)</span><span class="token comment">//append操作</span> <span class="token number">0x0072</span> <span class="token number">00114</span> <span class="token punctuation">(</span>slice<span class="token punctuation">.</span><span class="token keyword">go</span><span class="token punctuation">:</span><span class="token number">10</span><span class="token punctuation">)</span> PCDATA $<span class="token number">0</span><span class="token punctuation">,</span> $<span class="token number">1</span> <span class="token number">0x0072</span> <span class="token number">00114</span> <span class="token punctuation">(</span>slice<span class="token punctuation">.</span><span class="token keyword">go</span><span class="token punctuation">:</span><span class="token number">10</span><span class="token punctuation">)</span> MOVQ <span class="token function">40</span><span class="token punctuation">(</span>SP<span class="token punctuation">)</span><span class="token punctuation">,</span> AX <span class="token number">0x0077</span> <span class="token number">00119</span> <span class="token punctuation">(</span>slice<span class="token punctuation">.</span><span class="token keyword">go</span><span class="token punctuation">:</span><span class="token number">10</span><span class="token punctuation">)</span> MOVQ <span class="token function">48</span><span class="token punctuation">(</span>SP<span class="token punctuation">)</span><span class="token punctuation">,</span> CX <span class="token number">0x007c</span> <span class="token number">00124</span> <span class="token punctuation">(</span>slice<span class="token punctuation">.</span><span class="token keyword">go</span><span class="token punctuation">:</span><span class="token number">10</span><span class="token punctuation">)</span> MOVQ <span class="token function">56</span><span class="token punctuation">(</span>SP<span class="token punctuation">)</span><span class="token punctuation">,</span> DX <span class="token number">0x0081</span> <span class="token number">00129</span> <span class="token punctuation">(</span>slice<span class="token punctuation">.</span><span class="token keyword">go</span><span class="token punctuation">:</span><span class="token number">10</span><span class="token punctuation">)</span> MOVQ DX<span class="token punctuation">,</span> <span class="token string">""</span><span class="token punctuation">.</span>slice<span class="token punctuation">.</span><span class="token builtin">cap</span><span class="token operator"> </span><span class="token function">72</span><span class="token punctuation">(</span>SP<span class="token punctuation">)</span> <span class="token number">0x0086</span> <span class="token number">00134</span> <span class="token punctuation">(</span>slice<span class="token punctuation">.</span><span class="token keyword">go</span><span class="token punctuation">:</span><span class="token number">10</span><span class="token punctuation">)</span> MOVQ $<span class="token number">1</span><span class="token punctuation">,</span> <span class="token punctuation">(</span>AX<span class="token punctuation">)</span> <span class="token number">0x008d</span> <span class="token number">00141</span> <span class="token punctuation">(</span>slice<span class="token punctuation">.</span><span class="token keyword">go</span><span class="token punctuation">:</span><span class="token number">11</span><span class="token punctuation">)</span> PCDATA $<span class="token number">0</span><span class="token punctuation">,</span> $<span class="token number">0</span> <span class="token number">0x008d</span> <span class="token number">00141</span> <span class="token punctuation">(</span>slice<span class="token punctuation">.</span><span class="token keyword">go</span><span class="token punctuation">:</span><span class="token number">11</span><span class="token punctuation">)</span> MOVQ AX<span class="token punctuation">,</span> <span class="token punctuation">(</span>SP<span class="token punctuation">)</span> <span class="token number">0x0091</span> <span class="token number">00145</span> <span class="token punctuation">(</span>slice<span class="token punctuation">.</span><span class="token keyword">go</span><span class="token punctuation">:</span><span class="token number">10</span><span class="token punctuation">)</span> LEAQ <span class="token function">1</span><span class="token punctuation">(</span>CX<span class="token punctuation">)</span><span class="token punctuation">,</span> AX <span class="token number">0x0095</span> <span class="token number">00149</span> <span class="token punctuation">(</span>slice<span class="token punctuation">.</span><span class="token keyword">go</span><span class="token punctuation">:</span><span class="token number">10</span><span class="token punctuation">)</span> MOVQ AX<span class="token punctuation">,</span> <span class="token string">""</span><span class="token punctuation">.</span>slice<span class="token punctuation">.</span><span class="token builtin">len</span><span class="token operator"> </span><span class="token function">64</span><span class="token punctuation">(</span>SP<span class="token punctuation">)</span> <span class="token number">0x009a</span> <span class="token number">00154</span> <span class="token punctuation">(</span>slice<span class="token punctuation">.</span><span class="token keyword">go</span><span class="token punctuation">:</span><span class="token number">11</span><span class="token punctuation">)</span> MOVQ AX<span class="token punctuation">,</span> <span class="token function">8</span><span class="token punctuation">(</span>SP<span class="token punctuation">)</span> <span class="token number">0x009f</span> <span class="token number">00159</span> <span class="token punctuation">(</span>slice<span class="token punctuation">.</span><span class="token keyword">go</span><span class="token punctuation">:</span><span class="token number">11</span><span class="token punctuation">)</span> MOVQ DX<span class="token punctuation">,</span> <span class="token function">16</span><span class="token punctuation">(</span>SP<span class="token punctuation">)</span> <span class="token number">0x00a4</span> <span class="token number">00164</span> <span class="token punctuation">(</span>slice<span class="token punctuation">.</span><span class="token keyword">go</span><span class="token punctuation">:</span><span class="token number">11</span><span class="token punctuation">)</span> CALL runtime<span class="token punctuation">.</span><span class="token function">convTslice</span><span class="token punctuation">(</span>SB<span class="token punctuation">)</span><span class="token comment">//类型转换</span> <span class="token number">0x00a9</span> <span class="token number">00169</span> <span class="token punctuation">(</span>slice<span class="token punctuation">.</span><span class="token keyword">go</span><span class="token punctuation">:</span><span class="token number">11</span><span class="token punctuation">)</span> PCDATA $<span class="token number">0</span><span class="token punctuation">,</span> $<span class="token number">1</span> <span class="token number">0x00a9</span> <span class="token number">00169</span> <span class="token punctuation">(</span>slice<span class="token punctuation">.</span><span class="token keyword">go</span><span class="token punctuation">:</span><span class="token number">11</span><span class="token punctuation">)</span> MOVQ <span class="token function">24</span><span class="token punctuation">(</span>SP<span class="token punctuation">)</span><span class="token punctuation">,</span> AX <span class="token number">0x00ae</span> <span class="token number">00174</span> <span class="token punctuation">(</span>slice<span class="token punctuation">.</span><span class="token keyword">go</span><span class="token punctuation">:</span><span class="token number">11</span><span class="token punctuation">)</span> PCDATA $<span class="token number">0</span><span class="token punctuation">,</span> $<span class="token number">0</span> <span class="token number">0x00ae</span> <span class="token number">00174</span> <span class="token punctuation">(</span>slice<span class="token punctuation">.</span><span class="token keyword">go</span><span class="token punctuation">:</span><span class="token number">11</span><span class="token punctuation">)</span> PCDATA $<span class="token number">1</span><span class="token punctuation">,</span> $<span class="token number">1</span> <span class="token number">0x00ae</span> <span class="token number">00174</span> <span class="token punctuation">(</span>slice<span class="token punctuation">.</span><span class="token keyword">go</span><span class="token punctuation">:</span><span class="token number">11</span><span class="token punctuation">)</span> MOVQ AX<span class="token punctuation">,</span> <span class="token string">""</span><span class="token punctuation">.</span><span class="token punctuation">.</span>autotmp_33<span class="token operator"> </span><span class="token function">88</span><span class="token punctuation">(</span>SP<span class="token punctuation">)</span> <span class="token number">0x00b3</span> <span class="token number">00179</span> <span class="token punctuation">(</span>slice<span class="token punctuation">.</span><span class="token keyword">go</span><span class="token punctuation">:</span><span class="token number">11</span><span class="token punctuation">)</span> MOVQ <span class="token string">""</span><span class="token punctuation">.</span>slice<span class="token punctuation">.</span><span class="token builtin">len</span><span class="token operator"> </span><span class="token function">64</span><span class="token punctuation">(</span>SP<span class="token punctuation">)</span><span class="token punctuation">,</span> CX <span class="token number">0x00b8</span> <span class="token number">00184</span> <span class="token punctuation">(</span>slice<span class="token punctuation">.</span><span class="token keyword">go</span><span class="token punctuation">:</span><span class="token number">11</span><span class="token punctuation">)</span> MOVQ CX<span class="token punctuation">,</span> <span class="token punctuation">(</span>SP<span class="token punctuation">)</span> <span class="token number">0x00bc</span> <span class="token number">00188</span> <span class="token punctuation">(</span>slice<span class="token punctuation">.</span><span class="token keyword">go</span><span class="token punctuation">:</span><span class="token number">11</span><span class="token punctuation">)</span> CALL runtime<span class="token punctuation">.</span><span class="token function">convT64</span><span class="token punctuation">(</span>SB<span class="token punctuation">)</span> <span class="token number">0x00c1</span> <span class="token number">00193</span> <span class="token punctuation">(</span>slice<span class="token punctuation">.</span><span class="token keyword">go</span><span class="token punctuation">:</span><span class="token number">11</span><span class="token punctuation">)</span> PCDATA $<span class="token number">0</span><span class="token punctuation">,</span> $<span class="token number">1</span> <span class="token number">0x00c1</span> <span class="token number">00193</span> <span class="token punctuation">(</span>slice<span class="token punctuation">.</span><span class="token keyword">go</span><span class="token punctuation">:</span><span class="token number">11</span><span class="token punctuation">)</span> MOVQ <span class="token function">8</span><span class="token punctuation">(</span>SP<span class="token punctuation">)</span><span class="token punctuation">,</span> AX <span class="token number">0x00c6</span> <span class="token number">00198</span> <span class="token punctuation">(</span>slice<span class="token punctuation">.</span><span class="token keyword">go</span><span class="token punctuation">:</span><span class="token number">11</span><span class="token punctuation">)</span> PCDATA $<span class="token number">0</span><span class="token punctuation">,</span> $<span class="token number">0</span> <span class="token number">0x00c6</span> <span class="token number">00198</span> <span class="token punctuation">(</span>slice<span class="token punctuation">.</span><span class="token keyword">go</span><span class="token punctuation">:</span><span class="token number">11</span><span class="token punctuation">)</span> PCDATA $<span class="token number">1</span><span class="token punctuation">,</span> $<span class="token number">2</span> <span class="token number">0x00c6</span> <span class="token number">00198</span> <span class="token punctuation">(</span>slice<span class="token punctuation">.</span><span class="token keyword">go</span><span class="token punctuation">:</span><span class="token number">11</span><span class="token punctuation">)</span> MOVQ AX<span class="token punctuation">,</span> <span class="token string">""</span><span class="token punctuation">.</span><span class="token punctuation">.</span>autotmp_34<span class="token operator"> </span><span class="token function">80</span><span class="token punctuation">(</span>SP<span class="token punctuation">)</span> <span class="token number">0x00cb</span> <span class="token number">00203</span> <span class="token punctuation">(</span>slice<span class="token punctuation">.</span><span class="token keyword">go</span><span class="token punctuation">:</span><span class="token number">11</span><span class="token punctuation">)</span> MOVQ <span class="token string">""</span><span class="token punctuation">.</span>slice<span class="token punctuation">.</span><span class="token builtin">cap</span><span class="token operator"> </span><span class="token function">72</span><span class="token punctuation">(</span>SP<span class="token punctuation">)</span><span class="token punctuation">,</span> CX <span class="token number">0x00d0</span> <span class="token number">00208</span> <span class="token punctuation">(</span>slice<span class="token punctuation">.</span><span class="token keyword">go</span><span class="token punctuation">:</span><span class="token number">11</span><span class="token punctuation">)</span> MOVQ CX<span class="token punctuation">,</span> <span class="token punctuation">(</span>SP<span class="token punctuation">)</span> <span class="token number">0x00d4</span> <span class="token number">00212</span> <span class="token punctuation">(</span>slice<span class="token punctuation">.</span><span class="token keyword">go</span><span class="token punctuation">:</span><span class="token number">11</span><span class="token punctuation">)</span> CALL runtime<span class="token punctuation">.</span><span class="token function">convT64</span><span class="token punctuation">(</span>SB<span class="token punctuation">)</span> <span class="token number">0x00d9</span> <span class="token number">00217</span> <span class="token punctuation">(</span>slice<span class="token punctuation">.</span><span class="token keyword">go</span><span class="token punctuation">:</span><span class="token number">11</span><span class="token punctuation">)</span> PCDATA $<span class="token number">0</span><span class="token punctuation">,</span> $<span class="token number">1</span> <span class="token number">0x00d9</span> <span class="token number">00217</span> <span class="token punctuation">(</span>slice<span class="token punctuation">.</span><span class="token keyword">go</span><span class="token punctuation">:</span><span class="token number">11</span><span class="token punctuation">)</span> MOVQ <span class="token function">8</span><span class="token punctuation">(</span>SP<span class="token punctuation">)</span><span class="token punctuation">,</span> AX <span class="token number">0x00de</span> <span class="token number">00222</span> <span class="token punctuation">(</span>slice<span class="token punctuation">.</span><span class="token keyword">go</span><span class="token punctuation">:</span><span class="token number">11</span><span class="token punctuation">)</span> PCDATA $<span class="token number">1</span><span class="token punctuation">,</span> $<span class="token number">3</span> <span class="token number">0x00de</span> <span class="token number">00222</span> <span class="token punctuation">(</span>slice<span class="token punctuation">.</span><span class="token keyword">go</span><span class="token punctuation">:</span><span class="token number">11</span><span class="token punctuation">)</span> XORPS X0<span class="token punctuation">,</span> X0 </code></pre>

大家可能看到这里有点蒙,这是在干啥,其实我们只需要关注一些关键的信息就好了,主要是这几行:

<pre><code class="lang-go hljs"><span class="token number">0x0042</span> <span class="token number">00066</span> <span class="token punctuation">(</span>slice<span class="token punctuation">.</span><span class="token keyword">go</span><span class="token punctuation">:</span><span class="token number">9</span><span class="token punctuation">)</span> CALL runtime<span class="token punctuation">.</span><span class="token function">makeslice</span><span class="token punctuation">(</span>SB<span class="token punctuation">)</span><span class="token comment">//初始化slice</span> <span class="token number">0x006d</span> <span class="token number">00109</span> <span class="token punctuation">(</span>slice<span class="token punctuation">.</span><span class="token keyword">go</span><span class="token punctuation">:</span><span class="token number">10</span><span class="token punctuation">)</span> CALL runtime<span class="token punctuation">.</span><span class="token function">growslice</span><span class="token punctuation">(</span>SB<span class="token punctuation">)</span><span class="token comment">//append操作</span> <span class="token number">0x00a4</span> <span class="token number">00164</span> <span class="token punctuation">(</span>slice<span class="token punctuation">.</span><span class="token keyword">go</span><span class="token punctuation">:</span><span class="token number">11</span><span class="token punctuation">)</span> CALL runtime<span class="token punctuation">.</span><span class="token function">convTslice</span><span class="token punctuation">(</span>SB<span class="token punctuation">)</span><span class="token comment">//类型转换</span> <span class="token number">0x00bc</span> <span class="token number">00188</span> <span class="token punctuation">(</span>slice<span class="token punctuation">.</span><span class="token keyword">go</span><span class="token punctuation">:</span><span class="token number">11</span><span class="token punctuation">)</span> CALL runtime<span class="token punctuation">.</span><span class="token function">convT64</span><span class="token punctuation">(</span>SB<span class="token punctuation">)</span> <span class="token number">0x00d4</span> <span class="token number">00212</span> <span class="token punctuation">(</span>slice<span class="token punctuation">.</span><span class="token keyword">go</span><span class="token punctuation">:</span><span class="token number">11</span><span class="token punctuation">)</span> CALL runtime<span class="token punctuation">.</span><span class="token function">convT64</span><span class="token punctuation">(</span>SB<span class="token punctuation">)</span> </code></pre>

我们能观察出,底层是调用runtime中的makeslice方法来创建slice的,我们来看一下makeslice函数到底做了什么。

<pre><code class="lang-go hljs"> <span class="token keyword">func</span> <span class="token function">makeslice</span><span class="token punctuation">(</span>et <span class="token operator">*</span>_type<span class="token punctuation">,</span> <span class="token builtin">len</span><span class="token punctuation">,</span> <span class="token builtin">cap</span> <span class="token builtin">int</span><span class="token punctuation">)</span> unsafe<span class="token punctuation">.</span>Pointer <span class="token punctuation">{</span> mem<span class="token punctuation">,</span> overflow <span class="token operator">:=</span> math<span class="token punctuation">.</span><span class="token function">MulUintptr</span><span class="token punctuation">(</span>et<span class="token punctuation">.</span>size<span class="token punctuation">,</span> <span class="token function">uintptr</span><span class="token punctuation">(</span><span class="token builtin">cap</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token keyword">if</span> overflow <span class="token operator">||</span> mem <span class="token operator">></span> maxAlloc <span class="token operator">||</span> <span class="token builtin">len</span> <span class="token operator"><</span> <span class="token number">0</span> <span class="token operator">||</span> <span class="token builtin">len</span> <span class="token operator">></span> <span class="token builtin">cap</span> <span class="token punctuation">{</span> <span class="token comment">// NOTE: Produce a 'len out of range' error instead of a</span> <span class="token comment">// 'cap out of range' error when someone does make([]T, bignumber).</span> <span class="token comment">// 'cap out of range' is true too, but since the cap is only being</span> <span class="token comment">// supplied implicitly, saying len is clearer.</span> <span class="token comment">// See golang.org/issue/4085.</span> mem<span class="token punctuation">,</span> overflow <span class="token operator">:=</span> math<span class="token punctuation">.</span><span class="token function">MulUintptr</span><span class="token punctuation">(</span>et<span class="token punctuation">.</span>size<span class="token punctuation">,</span> <span class="token function">uintptr</span><span class="token punctuation">(</span><span class="token builtin">len</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token keyword">if</span> overflow <span class="token operator">||</span> mem <span class="token operator">></span> maxAlloc <span class="token operator">||</span> <span class="token builtin">len</span> <span class="token operator"><</span> <span class="token number">0</span> <span class="token punctuation">{</span> <span class="token function">panicmakeslicelen</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token function">panicmakeslicecap</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token comment">// Allocate an object of size bytes.</span> <span class="token comment">// Small objects are allocated from the per-P cache's free lists.</span> <span class="token comment">// Large objects (> 32 kB) are allocated straight from the heap.</span> <span class="token keyword">return</span> <span class="token function">mallocgc</span><span class="token punctuation">(</span>mem<span class="token punctuation">,</span> et<span class="token punctuation">,</span> <span class="token boolean">true</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token keyword">func</span> <span class="token function">panicmakeslicelen</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token function">panic</span><span class="token punctuation">(</span><span class="token function">errorString</span><span class="token punctuation">(</span><span class="token string">"makeslice: len out of range"</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token keyword">func</span> <span class="token function">panicmakeslicecap</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token function">panic</span><span class="token punctuation">(</span><span class="token function">errorString</span><span class="token punctuation">(</span><span class="token string">"makeslice: cap out of range"</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> </code></pre>

MulUintptr函数源码:

<pre><code class="lang-go hljs"> <span class="token keyword">package</span> math <span class="token keyword">import</span> <span class="token string">"runtime/internal/sys"</span> <span class="token keyword">const</span> MaxUintptr <span class="token operator">=</span> <span class="token operator">^</span><span class="token function">uintptr</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span> <span class="token comment">// MulUintptr returns a * b and whether the multiplication overflowed.</span> <span class="token comment">// On supported platforms this is an intrinsic lowered by the compiler.</span> <span class="token keyword">func</span> <span class="token function">MulUintptr</span><span class="token punctuation">(</span>a<span class="token punctuation">,</span> b <span class="token builtin">uintptr</span><span class="token punctuation">)</span> <span class="token punctuation">(</span><span class="token builtin">uintptr</span><span class="token punctuation">,</span> <span class="token builtin">bool</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">if</span> a<span class="token operator">|</span>b <span class="token operator"><</span> <span class="token number">1</span><span class="token operator"><<</span><span class="token punctuation">(</span><span class="token number">4</span><span class="token operator">*</span>sys<span class="token punctuation">.</span>PtrSize<span class="token punctuation">)</span> <span class="token operator">||</span> a <span class="token operator">==</span> <span class="token number">0</span> <span class="token punctuation">{</span><span class="token comment">//a|b < 1<<(4*8)</span> <span class="token keyword">return</span> a <span class="token operator">*</span> b<span class="token punctuation">,</span> <span class="token boolean">false</span> <span class="token punctuation">}</span> overflow <span class="token operator">:=</span> b <span class="token operator">></span> MaxUintptr<span class="token operator">/</span>a <span class="token keyword">return</span> a <span class="token operator">*</span> b<span class="token punctuation">,</span> overflow <span class="token punctuation">}</span> </code></pre>

简单来说,makeslice函数的工作主要就是计算slice所需内存大小,然后调用mallocgc进行内存的分配。计算slice所需内存又是通过MulUintptr来实现的,MulUintptr的源码我们也已经贴出,主要就是用切片中元素大小和切片的容量相乘计算出所需占用的内存空间,如果内存溢出,或者计算出的内存大小大于最大可分配内存,MulUintptr的overflow会返回true,makeslice就会报错。另外如果传入长度小于0或者长度小于容量,makeslice也会报错。

<h1>
append操作</h1>

首先我们来看一段程序:

<pre><code class="lang-go hljs"><span class="token keyword">package</span> main <span class="token keyword">import</span> <span class="token punctuation">(</span> <span class="token string">"fmt"</span> <span class="token string">"unsafe"</span> <span class="token punctuation">)</span> <span class="token keyword">func</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> slice <span class="token operator">:=</span> <span class="token function">make</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token builtin">int</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">10</span><span class="token punctuation">)</span> slice <span class="token operator">=</span> <span class="token function">append</span><span class="token punctuation">(</span>slice<span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">)</span> fmt<span class="token punctuation">.</span><span class="token function">Println</span><span class="token punctuation">(</span>unsafe<span class="token punctuation">.</span><span class="token function">Pointer</span><span class="token punctuation">(</span><span class="token operator">&</span>slice<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token function">len</span><span class="token punctuation">(</span>slice<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token function">cap</span><span class="token punctuation">(</span>slice<span class="token punctuation">)</span><span class="token punctuation">)</span> slice <span class="token operator">=</span> <span class="token function">append</span><span class="token punctuation">(</span>slice<span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">)</span> fmt<span class="token punctuation">.</span><span class="token function">Println</span><span class="token punctuation">(</span>unsafe<span class="token punctuation">.</span><span class="token function">Pointer</span><span class="token punctuation">(</span><span class="token operator">&</span>slice<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token function">len</span><span class="token punctuation">(</span>slice<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token function">cap</span><span class="token punctuation">(</span>slice<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> </code></pre>

我们直接给出结果:

<pre><code class="lang-go hljs"><span class="token number">0xc00009e000</span> <span class="token number">1</span> <span class="token number">10</span> <span class="token number">0xc00009e000</span> <span class="token number">2</span> <span class="token number">10</span> </code></pre>

我们可以看到,当slice容量足够时,我们往slice中append一个2,slice底层数组指向的内存地址没有发生改变;再看一段程序:

<pre><code class="lang-go hljs"><span class="token keyword">func</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> slice <span class="token operator">:=</span> <span class="token function">make</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token builtin">int</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">)</span> slice <span class="token operator">=</span> <span class="token function">append</span><span class="token punctuation">(</span>slice<span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">)</span> fmt<span class="token punctuation">.</span><span class="token function">Printf</span><span class="token punctuation">(</span><span class="token string">"%p %d %d\n"</span><span class="token punctuation">,</span> unsafe<span class="token punctuation">.</span><span class="token function">Pointer</span><span class="token punctuation">(</span><span class="token operator">&</span>slice<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token function">len</span><span class="token punctuation">(</span>slice<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token function">cap</span><span class="token punctuation">(</span>slice<span class="token punctuation">)</span><span class="token punctuation">)</span> slice <span class="token operator">=</span> <span class="token function">append</span><span class="token punctuation">(</span>slice<span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">)</span> fmt<span class="token punctuation">.</span><span class="token function">Printf</span><span class="token punctuation">(</span><span class="token string">"%p %d %d\n"</span><span class="token punctuation">,</span> unsafe<span class="token punctuation">.</span><span class="token function">Pointer</span><span class="token punctuation">(</span><span class="token operator">&</span>slice<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token function">len</span><span class="token punctuation">(</span>slice<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token function">cap</span><span class="token punctuation">(</span>slice<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> </code></pre>

输出结果是:

<pre><code class="lang-go hljs"><span class="token number">0xc00009a008</span> <span class="token number">1</span> <span class="token number">1</span> <span class="token number">0xc00009a030</span> <span class="token number">2</span> <span class="token number">2</span> </code></pre>

我们可以看到当往slice中append一个1后,slice底层数组的指针指向地址0xc00009a008,长度为1,容量为1。这时再往slice中append一个2,那么slice的容量不够了,此时底层数组会发生copy,会重新分配一块新的内存地址,容量也变成了2,所以我们会看到底层数组的指针指向地址发生了改变。根据之前汇编的结果我们知晓了,append操作其实是调用了runtime/slice.go中的growslice函数,我们来看下源码:

<pre><code class="lang-go hljs"><span class="token keyword">func</span> <span class="token function">growslice</span><span class="token punctuation">(</span>et <span class="token operator">*</span>_type<span class="token punctuation">,</span> old slice<span class="token punctuation">,</span> <span class="token builtin">cap</span> <span class="token builtin">int</span><span class="token punctuation">)</span> slice <span class="token punctuation">{</span> <span class="token operator">...</span> <span class="token operator">...</span> <span class="token keyword">if</span> <span class="token builtin">cap</span> <span class="token operator"><</span> old<span class="token punctuation">.</span><span class="token builtin">cap</span> <span class="token punctuation">{</span> <span class="token function">panic</span><span class="token punctuation">(</span><span class="token function">errorString</span><span class="token punctuation">(</span><span class="token string">"growslice: cap out of range"</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token keyword">if</span> et<span class="token punctuation">.</span>size <span class="token operator">==</span> <span class="token number">0</span> <span class="token punctuation">{</span> <span class="token comment">// append should not create a slice with nil pointer but non-zero len.</span> <span class="token comment">// We assume that append doesn't need to preserve old.array in this case.</span> <span class="token keyword">return</span> slice<span class="token punctuation">{</span>unsafe<span class="token punctuation">.</span><span class="token function">Pointer</span><span class="token punctuation">(</span><span class="token operator">&</span>zerobase<span class="token punctuation">)</span><span class="token punctuation">,</span> old<span class="token punctuation">.</span><span class="token builtin">len</span><span class="token punctuation">,</span> <span class="token builtin">cap</span><span class="token punctuation">}</span> <span class="token punctuation">}</span> newcap <span class="token operator">:=</span> old<span class="token punctuation">.</span><span class="token builtin">cap</span><span class="token comment">//1280</span> doublecap <span class="token operator">:=</span> newcap <span class="token operator"> </span> newcap<span class="token comment">//1280 1280=2560</span> <span class="token keyword">if</span> <span class="token builtin">cap</span> <span class="token operator">></span> doublecap <span class="token punctuation">{</span> newcap <span class="token operator">=</span> <span class="token builtin">cap</span> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span> <span class="token keyword">if</span> old<span class="token punctuation">.</span><span class="token builtin">len</span> <span class="token operator"><</span> <span class="token number">1024</span> <span class="token punctuation">{</span> newcap <span class="token operator">=</span> doublecap <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span> <span class="token comment">// Check 0 < newcap to detect overflow</span> <span class="token comment">// and prevent an infinite loop.</span> <span class="token keyword">for</span> <span class="token number">0</span> <span class="token operator"><</span> newcap <span class="token operator">&&</span> newcap <span class="token operator"><</span> <span class="token builtin">cap</span> <span class="token punctuation">{</span> newcap <span class="token operator"> =</span> newcap <span class="token operator">/</span> <span class="token number">4</span><span class="token comment">//1280*1.25=1600</span> <span class="token punctuation">}</span> <span class="token comment">// Set newcap to the requested cap when</span> <span class="token comment">// the newcap calculation overflowed.</span> <span class="token keyword">if</span> newcap <span class="token operator"><=</span> <span class="token number">0</span> <span class="token punctuation">{</span> newcap <span class="token operator">=</span> <span class="token builtin">cap</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token operator">...</span> <span class="token punctuation">}</span> </code></pre>

我们主要关注下cap的扩容规则,从源码中我们可以简单的总结出slice容量的扩容规则:当原slice的cap小于1024时,新slice的cap变为原来的2倍;原slice的cap大于1024时,新slice变为原来的1.25倍,我们写个程序来验证下:

<pre><code class="lang-go hljs"><span class="token keyword">package</span> main <span class="token keyword">import</span> <span class="token string">"fmt"</span> <span class="token keyword">func</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> slice <span class="token operator">:=</span> <span class="token function">make</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token builtin">int</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">)</span> oldCap <span class="token operator">:=</span> Golang 切片(slice)扩容机制源码剖析

Golang语言slice实现原理及使用方法
golang slice 最后一个元素_Go 常见的数据结构 Slice
[go语言]-slice实现的使用和基本原理
Golang slice 切片原理
理解 Go 编程中的 slice
Golang 深入 slice 实现原理及使用技巧
golang 没有名字参数_说说不知道的Golang中参数传递
想系统学习GO语言(Golang
jQuery源码分析系列

[关闭]
~ ~