使用了很多的slice,最近再准备面试的时候,才发现,自己对他是一知半解的,倘若问几个比较戏剧性的问题,发现自己还是第一时间无法给出正确答案的,所以今天,系统性的整理一下有关slice的一些知识点。
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两个元素,为什么不是切片的第一、二个元素
- 我一个值传递,调用FuncA,为啥可以在它函数体内,修改我切片的内容
有问题再洗洗看,就明白了切片的原理, 首先看第一个问题。实例化切片后,进行append操作
当我们在执行make([]int, 10)
这样的语句时,底层调用的是makeslice
函数。
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容量。
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,则返回范围的内存将归零。该方法的返回值是分配的资源的地址。
上面的动作完成之后,就是变量赋值了
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的数据类型由三部分组成。
在调用函数append进行增加元素的时候,我们看看slice又做了哪些操作
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底层的数据
本系列文章:
有任何问题,欢迎留言
有疑问加站长微信联系(非本文作者)