使用了不少的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操做緩存
當咱們在執行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底層的數據
本系列文章:
有任何問題,歡迎留言