func Array_1() {
var arr1 [3]int
arr1[0] = 1
arr1[1] = 2
arr1[2] = 3
fmt.Fprintf(os.Stdout, "%T - %v\n", arr1, arr1)
arr2 := [3]int{
1,
2,
3,
}
fmt.Fprintf(os.Stdout, "%T - %v\n", arr2, arr2)
arr3 := [3]int {1,2,3}
fmt.Fprintf(os.Stdout, "%T - %v\n", arr3, arr3)
arr4 := [3]int {
1,
2,
3}
fmt.Fprintf(os.Stdout, "%T - %v\n", arr4, arr4)
}
数组定义如上,注意逗号的使用。
下面看看数组是如何分配内存的:
func Array_1() {
arr2 := [3]int{
1,
2,
3,
}
arr2[0] = 4
}
0x0000 00000 (array.go:3) TEXT "".Array_1(SB), NOSPLIT|ABIInternal, $32-0
0x0000 00000 (array.go:3) SUBQ $32, SP
0x0004 00004 (array.go:3) MOVQ BP, 24(SP)
0x0009 00009 (array.go:3) LEAQ 24(SP), BP
...
0x000e 00014 (array.go:4) MOVQ $0, "".arr2(SP)
0x0016 00022 (array.go:4) XORPS X0, X0
0x0019 00025 (array.go:4) MOVUPS X0, "".arr2+8(SP)
0x001e 00030 (array.go:5) MOVQ $1, "".arr2(SP)
0x0026 00038 (array.go:6) MOVQ $2, "".arr2+8(SP)
0x002f 00047 (array.go:7) MOVQ $3, "".arr2+16(SP)
0x0038 00056 (array.go:9) MOVQ $0, "".arr2(SP)
0x0040 00064 (array.go:10) MOVQ 24(SP), BP
0x0045 00069 (array.go:10) ADDQ $32, SP
0x0049 00073 (array.go:10) RET
这里的array没涉及到动态分配内存,使用的只有栈空间,这个因为golang发现array只有在本函数内使用,不涉及传递。
func Array_1() {
arr2 := [3]int{
1,
2,
3,
}
Array_2(arr2)
}
func Array_2(arr [3]int) {
fmt.Println(arr)
}
"".Array_1 STEXT size=128 args=0x0 locals=0x38
0x0000 00000 (array.go:5) TEXT "".Array_1(SB), ABIInternal, $56-0
0x0000 00000 (array.go:5) MOVQ TLS, CX
0x0009 00009 (array.go:5) MOVQ (CX)(TLS*2), CX
0x0010 00016 (array.go:5) CMPQ SP, 16(CX)
0x0014 00020 (array.go:5) JLS 121
0x0016 00022 (array.go:5) SUBQ $56, SP
0x001a 00026 (array.go:5) MOVQ BP, 48(SP)
0x001f 00031 (array.go:5) LEAQ 48(SP), BP
...
0x0024 00036 (array.go:6) PCDATA $2, $0
0x0024 00036 (array.go:6) PCDATA $0, $0
0x0024 00036 (array.go:6) MOVQ $0, "".arr2+24(SP)
0x002d 00045 (array.go:6) XORPS X0, X0
0x0030 00048 (array.go:6) MOVUPS X0, "".arr2+32(SP)
0x0035 00053 (array.go:7) MOVQ $1, "".arr2+24(SP)
0x003e 00062 (array.go:8) MOVQ $2, "".arr2+32(SP)
0x0047 00071 (array.go:9) MOVQ $3, "".arr2+40(SP)
0x0050 00080 (array.go:11) MOVQ $1, (SP)
0x0058 00088 (array.go:11) MOVQ $2, 8(SP)
0x0061 00097 (array.go:11) MOVQ $3, 16(SP)
0x006a 00106 (array.go:11) CALL "".Array_2(SB)
0x006f 00111 (array.go:12) MOVQ 48(SP), BP
0x0074 00116 (array.go:12) ADDQ $56, SP
0x0078 00120 (array.go:12) RET
这会还没看到动态分配内存,但我么发现,调用Array_2也因此没有传递数组arr2的地址过去,而是把arr2的值传递过去了。
从这个例子可以看出,数组作为函数参数传递,是按照值传递方式传递的。
"".Array_2 STEXT size=273 args=0x18 locals=0x90
0x0000 00000 (array.go:14) TEXT "".Array_2(SB), ABIInternal, $144-24
0x0000 00000 (array.go:14) MOVQ TLS, CX
0x0009 00009 (array.go:14) MOVQ (CX)(TLS*2), CX
0x0010 00016 (array.go:14) LEAQ -16(SP), AX
0x0015 00021 (array.go:14) CMPQ AX, 16(CX)
0x0019 00025 (array.go:14) JLS 263
0x001f 00031 (array.go:14) SUBQ $144, SP
0x0026 00038 (array.go:14) MOVQ BP, 136(SP)
0x002e 00046 (array.go:14) LEAQ 136(SP), BP
...
0x0036 00054 (array.go:15) MOVQ "".arr+152(SP), AX
0x003e 00062 (array.go:15) MOVQ AX, ""..autotmp_2+48(SP)
0x0043 00067 (array.go:15) MOVUPS "".arr+160(SP), X0
0x004b 00075 (array.go:15) MOVUPS X0, ""..autotmp_2+56(SP)
0x0050 00080 (array.go:15) PCDATA $0, $1
0x0050 00080 (array.go:15) XORPS X0, X0
0x0053 00083 (array.go:15) MOVUPS X0, ""..autotmp_1+96(SP)
0x0058 00088 (array.go:15) PCDATA $2, $1
0x0058 00088 (array.go:15) PCDATA $0, $0
0x0058 00088 (array.go:15) LEAQ ""..autotmp_1+96(SP), AX
0x005d 00093 (array.go:15) PCDATA $2, $0
0x005d 00093 (array.go:15) PCDATA $0, $2
0x005d 00093 (array.go:15) MOVQ AX, ""..autotmp_4+72(SP)
0x0062 00098 (array.go:15) PCDATA $2, $1
0x0062 00098 (array.go:15) LEAQ type.[3]int(SB), AX
0x0069 00105 (array.go:15) PCDATA $2, $0
0x0069 00105 (array.go:15) MOVQ AX, (SP)
0x006d 00109 (array.go:15) PCDATA $2, $1
0x006d 00109 (array.go:15) LEAQ ""..autotmp_2+48(SP), AX
0x0072 00114 (array.go:15) PCDATA $2, $0
0x0072 00114 (array.go:15) MOVQ AX, 8(SP)
0x0077 00119 (array.go:15) CALL runtime.convT2Enoptr(SB)
0x007c 00124 (array.go:15) MOVQ 16(SP), AX
0x0081 00129 (array.go:15) PCDATA $2, $2
0x0081 00129 (array.go:15) MOVQ 24(SP), CX
0x0086 00134 (array.go:15) MOVQ AX, ""..autotmp_5+80(SP)
0x008b 00139 (array.go:15) MOVQ CX, ""..autotmp_5+88(SP)
0x0090 00144 (array.go:15) PCDATA $2, $3
0x0090 00144 (array.go:15) MOVQ ""..autotmp_4+72(SP), DX
0x0095 00149 (array.go:15) TESTB AL, (DX)
0x0097 00151 (array.go:15) MOVQ AX, (DX)
0x009a 00154 (array.go:15) PCDATA $2, $4
0x009a 00154 (array.go:15) LEAQ 8(DX), DI
...
0x009e 00158 (array.go:15) CMPL runtime.writeBarrier(SB), $0
0x00a5 00165 (array.go:15) JEQ 169
0x00a7 00167 (array.go:15) JMP 253
0x00a9 00169 (array.go:15) MOVQ CX, 8(DX)
0x00ad 00173 (array.go:15) JMP 175
0x00af 00175 (array.go:15) PCDATA $2, $1
0x00af 00175 (array.go:15) PCDATA $0, $0
0x00af 00175 (array.go:15) MOVQ ""..autotmp_4+72(SP), AX
0x00b4 00180 (array.go:15) TESTB AL, (AX)
0x00b6 00182 (array.go:15) JMP 184
0x00b8 00184 (array.go:15) MOVQ AX, ""..autotmp_3+112(SP)
0x00bd 00189 (array.go:15) MOVQ $1, ""..autotmp_3+120(SP)
0x00c6 00198 (array.go:15) MOVQ $1, ""..autotmp_3+128(SP)
0x00d2 00210 (array.go:15) PCDATA $2, $0
0x00d2 00210 (array.go:15) MOVQ AX, (SP)
0x00d6 00214 (array.go:15) MOVQ $1, 8(SP)
0x00df 00223 (array.go:15) MOVQ $1, 16(SP)
0x00e8 00232 (array.go:15) CALL fmt.Println(SB)
0x00ed 00237 (array.go:16) MOVQ 136(SP), BP
0x00f5 00245 (array.go:16) ADDQ $144, SP
0x00fc 00252 (array.go:16) RET
LEAQ type.[3]int(SB), AX runtime.convT2Enoptr(SB)
func convT2Enoptr(t *_type, elem unsafe.Pointer) (e eface) {
...
x := mallocgc(t.size, t, false)
memmove(x, elem, t.size)
e._type = t
e.data = x
return
}
这里我们终于看到涉及到动态内存分配了,也可以看到动态分配内存的array的底层数据结构是eface。
我们写段代码验证一下数组是值传递的:
func Array_1() {
arr2 := [3]int{
1,
2,
3,
}
fmt.Println(arr2)
Array_2(arr2)
fmt.Println(arr2)
}
func Array_2(arr [3]int) {
arr[0] = 4
arr[1] = 5
arr[2] = 6
}
=== RUN TestArray_1
[1 2 3]
[1 2 3]
--- PASS: TestArray_1 (0.00s)
PASS
确实,在Array_2中改变Array_1传入的数组的值,但其实没改,说明数组是值传递。
如果我们确实想修改arr2的值呢?
func Array_1() {
arr2 := [3]int{
1,
2,
3,
}
fmt.Println(arr2)
Array_2(&arr2)
fmt.Println(arr2)
}
func Array_2(arr *[3]int) {
arr[0] = 4
arr[1] = 5
arr[2] = 6
}
=== RUN TestArray_1
[1 2 3]
[4 5 6]
--- PASS: TestArray_1 (0.00s)
PASS
按照指针传递,果然修改成功了。
再看看len, cap:
func Array_1() {
arr2 := [3]int{
1,
2,
3,
}
fmt.Println(arr2, len(arr2), cap(arr2))
}
=== RUN TestArray_1
[1 2 3] 3 3
--- PASS: TestArray_1 (0.00s)
PASS
数组是编译期间就确定大小的,因此cap和len都是编译时的固定值。