我可能並不會使用golang slice

使用了不少的slice,最近再準備面試的時候,才發現,本身對他是隻知其一;不知其二的,假若問幾個比較戲劇性的問題,發現本身仍是第一時間沒法給出正確答案的,因此今天,系統性的整理一下有關slice的一些知識點。golang

package main

import (
	"fmt"
)

func main() {


	a := make([]int, 10)
	a = append(a, 1, 2)
	FuncA(a)
	fmt.Println(a)
	a[0] = 44
	FuncA(a)
	fmt.Println(a)
}

func FuncA(b []int) {
	b[0] =19
}
複製代碼

上面的示例輸出是:面試

[19 0 0 0 0 0 0 0 0 0 1 2]
[19 0 0 0 0 0 0 0 0 0 1 2]
複製代碼

從輸出看,通常狀況下,會有兩個疑問:數組

  • 我實例化一個切片以後,append兩個元素,爲何不是切片的第1、二個元素
  • 我一個值傳遞,調用FuncA,爲啥能夠在它函數體內,修改我切片的內容

有問題再洗洗看,就明白了切片的原理, 首先看第一個問題。實例化切片後,進行append操做緩存

當咱們在執行make([]int, 10)這樣的語句時,底層調用的是makeslice函數。bash

0x002f 00047 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:10)	LEAQ	type.int(SB), AX
	0x0036 00054 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:10)	PCDATA	$2, $0
	0x0036 00054 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:10)	MOVQ	AX, (SP)
	0x003a 00058 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:10)	MOVQ	$10, 8(SP)
	0x0043 00067 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:10)	MOVQ	$10, 16(SP)
	0x004c 00076 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:10)	CALL	runtime.makeslice(SB)
複製代碼

makeslice函數的三個參數爲,type.int, 10, 10 後面兩個參數是slice的長度和底層數組的長度,即slice容量。app

func makeslice(et *_type, len, cap int) unsafe.Pointer {
	mem, overflow := math.MulUintptr(et.size, uintptr(cap))
	if overflow || mem > maxAlloc || len < 0 || len > cap {
		// NOTE: Produce a 'len out of range' error instead of a
		// 'cap out of range' error when someone does make([]T, bignumber).
		// 'cap out of range' is true too, but since the cap is only being
		// supplied implicitly, saying len is clearer.
		// See golang.org/issue/4085.
		mem, overflow := math.MulUintptr(et.size, uintptr(len))
		if overflow || mem > maxAlloc || len < 0 {
			panicmakeslicelen()
		}
		panicmakeslicecap()
	}

	return mallocgc(mem, et, true)
}
複製代碼

makeslice首先作的是檢查棧溢出,若是溢出,直接panic,不然,調用mallocgc進行資源分配,看一下該函數的原型函數

func mallocgc(size uintptr, typ *_type, needzero bool) unsafe.Pointer 
複製代碼

分配一個大小爲size的對象。小對象是從per-P緩存的空閒列表中分配的。大對象(> 32 kB)是從堆中直接分配的。 mallocgc的參數爲,要分配的內存大小:mem= type.int.size * cap。第二個參數爲元素類型。第三個參數是個bool值,若是needzero爲true,則返回範圍的內存將歸零。該方法的返回值是分配的資源的地址。 上面的動做完成以後,就是變量賦值了post

0x004c 00076 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:10)	CALL	runtime.makeslice(SB)
	0x0051 00081 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:10)	PCDATA	$2, $1
	0x0051 00081 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:10)	MOVQ	24(SP), AX
	0x0056 00086 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:10)	MOVQ	AX, "".a+112(SP)
	0x005b 00091 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:10)	MOVQ	$10, "".a+120(SP)
	0x0064 00100 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:10)	MOVQ	$10, "".a+128(SP)
複製代碼

該賦值動做涵蓋三部分,第一部分就是分配的內存地址,第二部分就是slice長度,第三部分就是底層數組的長度,這也印證了,slice的數據類型由三部分組成。ui

在調用函數append進行增長元素的時候,咱們看看slice又作了哪些操做this

0x0070 00112 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:11)	JMP	114
	0x0072 00114 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:11)	PCDATA	$2, $2
	0x0072 00114 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:11)	LEAQ	type.int(SB), CX
	0x0079 00121 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:11)	PCDATA	$2, $1
	0x0079 00121 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:11)	MOVQ	CX, (SP)
	0x007d 00125 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:11)	PCDATA	$2, $0
	0x007d 00125 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:11)	MOVQ	AX, 8(SP)
	0x0082 00130 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:11)	MOVQ	$10, 16(SP)
	0x008b 00139 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:11)	MOVQ	$10, 24(SP)
	0x0094 00148 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:11)	MOVQ	$12, 32(SP)
	0x009d 00157 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:11)	CALL	runtime.growslice(SB)
	0x00a2 00162 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:11)	PCDATA	$2, $1
	0x00a2 00162 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:11)	MOVQ	40(SP), AX
	0x00a7 00167 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:11)	MOVQ	48(SP), CX
	0x00ac 00172 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:11)	MOVQ	56(SP), DX
	0x00b1 00177 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:11)	ADDQ	$2, CX
	0x00b5 00181 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:11)	JMP	183
	0x00b7 00183 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:11)	MOVQ	$1, 80(AX)
	0x00bf 00191 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:11)	MOVQ	$2, 88(AX)
	0x00c7 00199 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:11)	PCDATA	$0, $1
	0x00c7 00199 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:11)	MOVQ	AX, "".a+112(SP)
	0x00cc 00204 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:11)	MOVQ	CX, "".a+120(SP)
	0x00d1 00209 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:11)	MOVQ	DX, "".a+128(SP)
複製代碼

咱們發現,在增長元素以前,先對slice進行了一次擴容,調用了runtime.growslice函數,該函數原型是

func growslice(et *_type, old slice, cap int) slice

該函數提供了三個參數,第一個參數是元素類型type.int,第二個參數是擴容前原始slice,第三個參數是新slice的容量,該例子中是12.該函數調用完成後,返回新的slice. 新的slice進行了一個長度增長2的動做後,把新的元素放到了slice中數組中是放在偏移量爲80和88的地址裏的。

0x00b7 00183 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:11)	MOVQ	$1, 80(AX)
	0x00bf 00191 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:11)	MOVQ	$2, 88(AX)
複製代碼

這也就是第一個問題,其將數據是追加到數組的最後的。

全部動做完成以後,又從新進行了一次賦值操做

0x00c7 00199 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:11)	MOVQ	AX, "".a+112(SP)
	0x00cc 00204 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:11)	MOVQ	CX, "".a+120(SP)
	0x00d1 00209 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:11)	MOVQ	DX, "".a+128(SP)
複製代碼

以後就開始了FuncA函數的調用

0x00d9 00217 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:12)	MOVQ	AX, (SP)
	0x00dd 00221 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:12)	MOVQ	CX, 8(SP)
	0x00e2 00226 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:12)	MOVQ	DX, 16(SP)
	0x00e7 00231 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:12)	CALL	"".FuncA(SB)
複製代碼

這次調用很是有意思的是,參數上,將a slice的底層切片結構提供給了FuncA,這也就印證了第二個問題,爲啥我在FuncA中對slice的元素修改,能夠影響到個人原始slice. 再看一下FuncA的函數調用狀況

"".FuncA STEXT nosplit size=50 args=0x18 locals=0x8
	0x0000 00000 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:19)	TEXT	"".FuncA(SB), NOSPLIT|ABIInternal, $8-24
	0x0000 00000 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:19)	SUBQ	$8, SP
	0x0004 00004 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:19)	MOVQ	BP, (SP)
	0x0008 00008 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:19)	LEAQ	(SP), BP
	0x000c 00012 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:19)	FUNCDATA	$0, gclocals·1a65e721a2ccc325b382662e7ffee780(SB)
	0x000c 00012 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:19)	FUNCDATA	$1, gclocals·69c1753bd5f81501d95132d08af04464(SB)
	0x000c 00012 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:19)	FUNCDATA	$3, gclocals·9fb7f0986f647f17cb53dda1484e0f7a(SB)
	0x000c 00012 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:20)	PCDATA	$2, $1
	0x000c 00012 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:20)	PCDATA	$0, $0
	0x000c 00012 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:20)	MOVQ	"".b+16(SP), AX
	0x0011 00017 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:20)	PCDATA	$0, $1
	0x0011 00017 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:20)	CMPQ	"".b+24(SP), $0
	0x0017 00023 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:20)	JHI	27
	0x0019 00025 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:20)	JMP	43
	0x001b 00027 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:20)	PCDATA	$2, $0
	0x001b 00027 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:20)	MOVQ	$19, (AX)
	0x0022 00034 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:21)	MOVQ	(SP), BP
	0x0026 00038 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:21)	ADDQ	$8, SP
	0x002a 00042 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:21)	RET
	0x002b 00043 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:20)	CALL	runtime.panicindex(SB)
	0x0030 00048 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:20)	UNDEF
	0x0000 48 83 ec 08 48 89 2c 24 48 8d 2c 24 48 8b 44 24  H...H.,$H.,$H.D$
	0x0010 10 48 83 7c 24 18 00 77 02 eb 10 48 c7 00 13 00  .H.|$..w...H....
	0x0020 00 00 48 8b 2c 24 48 83 c4 08 c3 e8 00 00 00 00  ..H.,$H.........
	0x0030 0f 0b                                            ..
	rel 44+4 t=8 runtime.panicindex+0
複製代碼

首先進行一個索引的比較,若是是0,則執行賦值。而後收回資源返回。

再來看看幾個有意思的示例:

package main

import (
	"fmt"
)

func main() {
	a := make([]int, 10)
	FuncA(a)
	fmt.Println(a)
}

func FuncA(b []int) {
	b = append(b, 1, 2)
}
複製代碼

仍是相同的例子,只不過,咱們在FuncA中執行的是append操做,而不是索引的賦值操做。首先看一下該程序的輸出:

[0 0 0 0 0 0 0 0 0 0]
複製代碼

發現麼,原始slice的值並無修改,這特麼的爲啥,不是能夠修改麼?

0x0021 00033 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:11)	MOVQ	"".b+96(SP), AX
	0x0026 00038 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:11)	LEAQ	2(AX), CX
	0x002a 00042 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:11)	PCDATA	$2, $1
	0x002a 00042 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:11)	MOVQ	"".b+88(SP), DX
	0x002f 00047 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:11)	PCDATA	$0, $1
	0x002f 00047 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:11)	MOVQ	"".b+104(SP), BX
	0x0034 00052 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:11)	CMPQ	CX, BX
	0x0037 00055 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:11)	JLS	59
	0x0039 00057 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:11)	JMP	103
	0x003b 00059 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:11)	PCDATA	$2, $-2
	0x003b 00059 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:11)	PCDATA	$0, $-2
	0x003b 00059 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:11)	JMP	61
	0x003d 00061 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:11)	PCDATA	$2, $1
	0x003d 00061 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:11)	PCDATA	$0, $1
	0x003d 00061 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:11)	MOVQ	$1, (DX)(AX*8)
	0x0045 00069 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:11)	MOVQ	$2, 8(DX)(AX*8)
	0x004e 00078 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:11)	PCDATA	$2, $0
	0x004e 00078 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:11)	MOVQ	DX, "".b+88(SP)
	0x0053 00083 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:11)	MOVQ	CX, "".b+96(SP)
	0x0058 00088 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:11)	MOVQ	BX, "".b+104(SP)
	0x005d 00093 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:12)	MOVQ	72(SP), BP
	0x0062 00098 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:12)	ADDQ	$80, SP
	0x0066 00102 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:12)	RET
	0x0067 00103 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:11)	PCDATA	$2, $1
	0x0067 00103 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:11)	MOVQ	AX, ""..autotmp_1+64(SP)
	0x006c 00108 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:11)	PCDATA	$2, $2
	0x006c 00108 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:11)	LEAQ	type.int(SB), SI
	0x0073 00115 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:11)	PCDATA	$2, $1
	0x0073 00115 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:11)	MOVQ	SI, (SP)
	0x0077 00119 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:11)	PCDATA	$2, $0
	0x0077 00119 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:11)	MOVQ	DX, 8(SP)
	0x007c 00124 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:11)	MOVQ	AX, 16(SP)
	0x0081 00129 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:11)	MOVQ	BX, 24(SP)
	0x0086 00134 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:11)	MOVQ	CX, 32(SP)
	0x008b 00139 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:11)	CALL	runtime.growslice(SB)
	0x0090 00144 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:11)	PCDATA	$2, $1
	0x0090 00144 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:11)	MOVQ	40(SP), DX
	0x0095 00149 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:11)	MOVQ	48(SP), AX
	0x009a 00154 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:11)	MOVQ	56(SP), BX
	0x009f 00159 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:11)	LEAQ	2(AX), CX
	0x00a3 00163 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:11)	MOVQ	""..autotmp_1+64(SP), AX
	0x00a8 00168 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:11)	JMP	61
複製代碼

首先判斷是否須要growslice,若是須要,先進行growslice操做,以後再進行元素的追加,元素的追加也是很簡單的,就是寄存器的地址運算,而後將值移動到指定的。

0x003d 00061 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:11)	MOVQ	$1, (DX)(AX*8)
	0x0045 00069 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:11)	MOVQ	$2, 8(DX)(AX*8)
複製代碼

完成後進行賦值操做

0x004e 00078 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:11)	MOVQ	DX, "".b+88(SP)
	0x0053 00083 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:11)	MOVQ	CX, "".b+96(SP)
	0x0058 00088 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:11)	MOVQ	BX, "".b+104(SP)
複製代碼

上面的這個函數的操做,是在擴容的狀況下,新分配的底層數組DX寄存器,+AX寄存器的偏移後,進行的賦值,此時b做爲獨立的slice,值是放到該slice中的底層數組中的。至於FuncA函數返回後,對於原始的slice就並無產生什麼影響。 下面的示例更能說明狀況

package main

import (
	"fmt"
)

func main() {
	a := make([]int, 10, 10)
	b := a
	b = append(b ,1,2)
	b[0] =19
	fmt.Println(a)
}
複製代碼

結果是[0 0 0 0 0 0 0 0 0 0].append在操做時,會判斷,是否須要擴容,就是其cap(底層數組的長度)是否夠用.若是不夠用,進行了擴容的操做,那麼會分配一個新的基礎數組,那麼b和a就沒了聯繫,並不會再共用同一個底層數組,可是若是並無進行擴容操做,底層數組夠用,那麼其實他們仍是會共用同一個底層數組,只不過其所看到的內容不一樣罷了。

上面的例子仍是比較極端的狀況,再看一個不用進行growslice操做的狀況,看看會不會有什麼影響;

package main



func main() {
	a := make([]int, 10, 20)
	FuncA(a)
}

func FuncA(b []int) {
	b = append(b, 1, 2)
}
複製代碼

首先看一下其輸出狀況:

[0 0 0 0 0 0 0 0 0 0]
複製代碼

奇怪,我分配了那麼大cap的slice,在FuncA中,並不須要進行growslice操做,爲何仍是沒有影響到原始的slice呢 .咱們有理由懷疑,這一切的緣由都是append函數,致使的,那麼append到底進行了什麼操做呢?

append函數是golang內建的函數,具體聲明爲:

// The append built-in function appends elements to the end of a slice. If
// it has sufficient capacity, the destination is resliced to accommodate the
// new elements. If it does not, a new underlying array will be allocated.
// Append returns the updated slice. It is therefore necessary to store the
// result of append, often in the variable holding the slice itself:
//	slice = append(slice, elem1, elem2)
//	slice = append(slice, anotherSlice...)
// As a special case, it is legal to append a string to a byte slice, like this:
//	slice = append([]byte("hello "), "world"...)
func append(slice []Type, elems ...Type) []Type
複製代碼

就是說,內建的append函數將元素追加到slice尾部,若是其有足夠的空間,所以能夠元素追加到目標切片中,以容納新元素。 若是沒有,將分配一個新的基礎數組。 追加返回更新的切片。 所以,有必要將append的結果存儲在一般包含切片自己的變量中,

slice = append(slice, elem1, elem2)
slice = append(slice, anotherSlice...)
複製代碼

具體到,更簡單的操做,來看一下:

package main

import (
	"fmt"
)

func main() {
	a := make([]int, 10, 20)
	b := a
	b = append(b ,1,2)
	fmt.Println(a)
}
複製代碼

其結果同樣的,輸出是[0 0 0 0 0 0 0 0 0 0]

可是經過b能夠實現對a slice底層數組的索引修改,好比

package main

import (
	"fmt"
)

func main() {
	a := make([]int, 10, 20)
	b := a
	b = append(b ,1,2)
	b[0] =19
	fmt.Println(a)
}
複製代碼

輸出是:[19 0 0 0 0 0 0 0 0 0].其底層數組中,指定是同一個數組,只是append的操做,並不影響a slice罷了。 a和b僅僅共用其相同的部分,其追加的東西並不會共享。

還有一種比較有意思的狀況

package main

import (
	"fmt"
)

func main() {
	a := make([]int, 10, 10)
	FuncA(a)
	fmt.Println(a)
}

func FuncA(b []int) {
	for i, v :=range b {
		v += 1
	}
}
複製代碼

其結果輸出是:[0 0 0 0 0 0 0 0 0 0]

"".FuncA STEXT nosplit size=139 args=0x18 locals=0x40
	0x0000 00000 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:9)	TEXT	"".FuncA(SB), NOSPLIT|ABIInternal, $64-24
	0x0000 00000 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:9)	SUBQ	$64, SP
	0x0004 00004 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:9)	MOVQ	BP, 56(SP)
	0x0009 00009 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:9)	LEAQ	56(SP), BP
	0x000e 00014 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:9)	FUNCDATA	$0, gclocals·2d7c1615616d4cf40d01b3385155ed6e(SB)
	0x000e 00014 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:9)	FUNCDATA	$1, gclocals·6d81f9fc90b2254ac2f1067a7bf2c67c(SB)
	0x000e 00014 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:9)	FUNCDATA	$3, gclocals·db688afbc90e26183a53c9ad23b80c29(SB)
	0x000e 00014 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:10)	PCDATA	$2, $0
	0x000e 00014 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:10)	PCDATA	$0, $0
	0x000e 00014 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:10)	MOVQ	"".b+88(SP), AX
	0x0013 00019 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:10)	MOVQ	"".b+80(SP), CX
	0x0018 00024 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:10)	PCDATA	$2, $1
	0x0018 00024 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:10)	PCDATA	$0, $1
	0x0018 00024 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:10)	MOVQ	"".b+72(SP), DX
	0x001d 00029 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:10)	PCDATA	$2, $0
	0x001d 00029 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:10)	PCDATA	$0, $2
	0x001d 00029 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:10)	MOVQ	DX, ""..autotmp_2+32(SP)
	0x0022 00034 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:10)	MOVQ	CX, ""..autotmp_2+40(SP)
	0x0027 00039 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:10)	MOVQ	AX, ""..autotmp_2+48(SP)
	0x002c 00044 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:10)	MOVQ	$0, ""..autotmp_3+24(SP)
	0x0035 00053 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:10)	MOVQ	""..autotmp_2+40(SP), AX
	0x003a 00058 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:10)	MOVQ	AX, ""..autotmp_4+16(SP)
	0x003f 00063 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:10)	JMP	65
	0x0041 00065 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:10)	MOVQ	""..autotmp_4+16(SP), AX
	0x0046 00070 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:10)	CMPQ	""..autotmp_3+24(SP), AX
	0x004b 00075 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:10)	JLT	79
	0x004d 00077 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:10)	JMP	129
	0x004f 00079 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:10)	MOVQ	""..autotmp_3+24(SP), AX
	0x0054 00084 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:10)	SHLQ	$3, AX
	0x0058 00088 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:10)	PCDATA	$2, $2
	0x0058 00088 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:10)	ADDQ	""..autotmp_2+32(SP), AX
	0x005d 00093 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:10)	PCDATA	$2, $0
	0x005d 00093 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:10)	MOVQ	(AX), AX
	0x0060 00096 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:10)	MOVQ	AX, ""..autotmp_5+8(SP)
	0x0065 00101 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:10)	MOVQ	AX, "".v(SP)
	0x0069 00105 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:11)	INCQ	AX
	0x006c 00108 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:11)	MOVQ	AX, "".v(SP)
	0x0070 00112 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:11)	JMP	114
	0x0072 00114 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:10)	MOVQ	""..autotmp_3+24(SP), AX
	0x0077 00119 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:10)	INCQ	AX
	0x007a 00122 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:10)	MOVQ	AX, ""..autotmp_3+24(SP)
	0x007f 00127 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:10)	JMP	65
	0x0081 00129 (<unknown line number>)	PCDATA	$0, $1
	0x0081 00129 (<unknown line number>)	MOVQ	56(SP), BP
	0x0086 00134 (<unknown line number>)	ADDQ	$64, SP
	0x008a 00138 (<unknown line number>)	RET
	0x0000 48 83 ec 40 48 89 6c 24 38 48 8d 6c 24 38 48 8b  H..@H.l$8H.l$8H.
	0x0010 44 24 58 48 8b 4c 24 50 48 8b 54 24 48 48 89 54  D$XH.L$PH.T$HH.T
	0x0020 24 20 48 89 4c 24 28 48 89 44 24 30 48 c7 44 24  $ H.L$(H.D$0H.D$
	0x0030 18 00 00 00 00 48 8b 44 24 28 48 89 44 24 10 eb  .....H.D$(H.D$..
	0x0040 00 48 8b 44 24 10 48 39 44 24 18 7c 02 eb 32 48  .H.D$.H9D$.|..2H
	0x0050 8b 44 24 18 48 c1 e0 03 48 03 44 24 20 48 8b 00  .D$.H...H.D$ H..
	0x0060 48 89 44 24 08 48 89 04 24 48 ff c0 48 89 04 24  H.D$.H..$H..H..$
	0x0070 eb 00 48 8b 44 24 18 48 ff c0 48 89 44 24 18 eb  ..H.D$.H..H.D$..
	0x0080 c0 48 8b 6c 24 38 48 83 c4 40 c3                 .H.l$8H..@.
複製代碼

若是改爲以下形式,結果就不同了:

package main

import (
	"fmt"
)

func main() {
	a := make([]int, 10, 10)
	FuncA(a)
	fmt.Println(a)
}

func FuncA(b []int) {
	for i, _ :=range b {
		b[i] += 1
	}
}
複製代碼

其結果輸出是:[1 1 1 1 1 1 1 1 1 1]

"".FuncA STEXT nosplit size=135 args=0x18 locals=0x20
	0x0000 00000 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:9)	TEXT	"".FuncA(SB), NOSPLIT|ABIInternal, $32-24
	0x0000 00000 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:9)	SUBQ	$32, SP
	0x0004 00004 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:9)	MOVQ	BP, 24(SP)
	0x0009 00009 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:9)	LEAQ	24(SP), BP
	0x000e 00014 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:9)	FUNCDATA	$0, gclocals·1a65e721a2ccc325b382662e7ffee780(SB)
	0x000e 00014 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:9)	FUNCDATA	$1, gclocals·69c1753bd5f81501d95132d08af04464(SB)
	0x000e 00014 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:9)	FUNCDATA	$3, gclocals·7cae486b9f11463edb9d0e91d30ff0f7(SB)
	0x000e 00014 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:10)	PCDATA	$2, $0
	0x000e 00014 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:10)	PCDATA	$0, $0
	0x000e 00014 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:10)	MOVQ	$0, ""..autotmp_2+16(SP)
	0x0017 00023 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:10)	MOVQ	"".b+48(SP), AX
	0x001c 00028 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:10)	MOVQ	AX, ""..autotmp_3+8(SP)
	0x0021 00033 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:10)	JMP	35
	0x0023 00035 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:10)	MOVQ	""..autotmp_3+8(SP), AX
	0x0028 00040 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:10)	CMPQ	""..autotmp_2+16(SP), AX
	0x002d 00045 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:10)	JLT	49
	0x002f 00047 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:10)	JMP	118
	0x0031 00049 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:10)	MOVQ	""..autotmp_2+16(SP), AX
	0x0036 00054 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:10)	MOVQ	AX, "".i(SP)
	0x003a 00058 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:11)	PCDATA	$2, $1
	0x003a 00058 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:11)	MOVQ	"".b+40(SP), CX
	0x003f 00063 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:11)	CMPQ	"".b+48(SP), AX
	0x0044 00068 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:11)	JHI	72
	0x0046 00070 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:11)	JMP	116
	0x0048 00072 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:11)	PCDATA	$2, $0
	0x0048 00072 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:11)	MOVQ	(CX)(AX*8), CX
	0x004c 00076 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:11)	PCDATA	$2, $2
	0x004c 00076 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:11)	MOVQ	"".b+40(SP), DX
	0x0051 00081 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:11)	INCQ	CX
	0x0054 00084 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:11)	CMPQ	"".b+48(SP), AX
	0x0059 00089 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:11)	JHI	93
	0x005b 00091 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:11)	JMP	114
	0x005d 00093 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:11)	PCDATA	$2, $0
	0x005d 00093 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:11)	MOVQ	CX, (DX)(AX*8)
	0x0061 00097 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:11)	JMP	99
	0x0063 00099 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:10)	MOVQ	""..autotmp_2+16(SP), AX
	0x0068 00104 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:10)	INCQ	AX
	0x006b 00107 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:10)	MOVQ	AX, ""..autotmp_2+16(SP)
	0x0070 00112 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:10)	JMP	35
	0x0072 00114 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:11)	PCDATA	$2, $-2
	0x0072 00114 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:11)	PCDATA	$0, $-2
	0x0072 00114 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:11)	JMP	128
	0x0074 00116 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:11)	JMP	128
	0x0076 00118 (<unknown line number>)	MOVQ	24(SP), BP
	0x007b 00123 (<unknown line number>)	ADDQ	$32, SP
	0x007f 00127 (<unknown line number>)	RET
	0x0080 00128 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:11)	PCDATA	$2, $0
	0x0080 00128 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:11)	PCDATA	$0, $1
	0x0080 00128 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:11)	CALL	runtime.panicindex(SB)
	0x0085 00133 (/Users/zhaojunwei/workspace/src/just.for.test/sour_slicetest/main2.go:11)	UNDEF
	0x0000 48 83 ec 20 48 89 6c 24 18 48 8d 6c 24 18 48 c7  H.. H.l$.H.l$.H.
	0x0010 44 24 10 00 00 00 00 48 8b 44 24 30 48 89 44 24  D$.....H.D$0H.D$
	0x0020 08 eb 00 48 8b 44 24 08 48 39 44 24 10 7c 02 eb  ...H.D$.H9D$.|..
	0x0030 45 48 8b 44 24 10 48 89 04 24 48 8b 4c 24 28 48  EH.D$.H..$H.L$(H
	0x0040 39 44 24 30 77 02 eb 2c 48 8b 0c c1 48 8b 54 24  9D$0w..,H...H.T$
	0x0050 28 48 ff c1 48 39 44 24 30 77 02 eb 15 48 89 0c  (H..H9D$0w...H..
	0x0060 c2 eb 00 48 8b 44 24 10 48 ff c0 48 89 44 24 10  ...H.D$.H..H.D$.
	0x0070 eb b1 eb 0c eb 0a 48 8b 6c 24 18 48 83 c4 20 c3  ......H.l$.H.. .
	0x0080 e8 00 00 00 00 0f 0b                             .......
	rel 129+4 t=8 runtime.panicindex+0
複製代碼

總結:

1.append操做在無需擴容的狀況下,新的slice和老slice共用底層的數組,經過索引對新的slice的修改,會影響到老的slice

2.所謂共用底層數組,僅僅共用其公共部分,至於特有的部分,各方也是沒法修改和查看的

3.在for循環遍歷slice時,value是一次值copy,對其的修改,並不會影響到slice底層的數據

本系列文章:

有任何問題,歡迎留言

相關文章
相關標籤/搜索