array

说明

​ mfp包来自:github.com/before80/utils/mfp

数组的底层数据结构

​ 在Go语言中,数组的底层定义主要涉及到Go语言的运行时和编译器部分,具体的实现和定义分散在多个文件中。

C创建

一维数组

直接创建

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
var verbs = []string{"T", "v", "#v"}
var a0 [3]int
var a1 = [3]int{1, 2, 3}
var a2 [3]int = [3]int{1, 2, 3}
var a3 = [...]int{1, 2, 3}
ad1 := [...]int{1, 2, 3}
mfp.PrintFmtVal("a0", a0, verbs)
mfp.PrintFmtVal("a1", a1, verbs)
mfp.PrintFmtVal("a2", a2, verbs)
mfp.PrintFmtVal("a3", a3, verbs)
mfp.PrintFmtVal("ad1", ad1, verbs)
a0:     %T -> [3]int | %v -> [0 0 0] | %#v -> [3]int{0, 0, 0}
a1:     %T -> [3]int | %v -> [1 2 3] | %#v -> [3]int{1, 2, 3}
a2:     %T -> [3]int | %v -> [1 2 3] | %#v -> [3]int{1, 2, 3}
a3:     %T -> [3]int | %v -> [1 2 3] | %#v -> [3]int{1, 2, 3}
ad1:    %T -> [3]int | %v -> [1 2 3] | %#v -> [3]int{1, 2, 3}

是否可以通过make创建?

​ => 不可以,make函数自能用于slice、map、channel。

1
2
3
4
//a4 := make([3]int{1, 2, 3}, 3, 3) // 报错:[3]int{…} is not a type
//a4 := make([3]int{}, 3, 3) // 报错:[3]int{} is not a type
//a4 := make([3]int, 3, 3) // 报错:invalid argument: cannot make [3]int; type must be slice, map, or channel
//a4 := make([3]int) // 报错: invalid argument: cannot make [3]int; type must be slice, map, or channel	

是否可以通过new创建?

​ => 可以

1
2
3
a5 := new([3]int)
mfp.PrintFmtVal("a5", a5, verbs)
mfp.PrintFmtVal("*a5", *a5, verbs)
a5:     %T -> *[3]int | %v -> &[0 0 0] | %#v -> &[3]int{0, 0, 0}
*a5:    %T -> [3]int | %v -> [0 0 0] | %#v -> [3]int{0, 0, 0}

多维数组

​ 从一维数组的创建中可以推测出,多维数组的创建也是不可以通过make进行创建,new可以进行创建。

​ 根据以下代码和运行结果,我们还可以发现在使用数组字面量直接创建多维数组的时候,只能在第一维的位置上使用...,而不能在后续维度上使用,否则编译时报错。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
fmt.Println("多维数组")
fmt.Println("二维数组")
var a6 = [3][3]int{{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}
var a7 [3][3]int = [3][3]int{{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}
var a8 = [...][3]int{{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}
//var a9 = [...][...]int{{1, 2, 3}, {4, 5, 6}, {7, 8, 9}} // 报错:invalid use of [...] array (outside a composite literal)
ad2 := [...][3]int{{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}
ad20 := new([3][3]int)
mfp.PrintFmtVal("a6", a6, verbs)
mfp.PrintFmtVal("a7", a7, verbs)
mfp.PrintFmtVal("a8", a8, verbs)
//mfp.PrintFmtVal("a9", a9, verbs)
mfp.PrintFmtVal("ad2", ad2, verbs)
mfp.PrintFmtVal("ad20", ad20, verbs)
mfp.PrintFmtVal("*ad20", *ad20, verbs)

fmt.Println("三维数组")
var a10 = [2][2][2]int{{{1, 2}, {3, 4}}, {{5, 6}, {7, 8}}}
var a11 [2][2][2]int = [2][2][2]int{{{1, 2}, {3, 4}}, {{5, 6}, {7, 8}}}
var a12 = [...][2][2]int{{{1, 2}, {3, 4}}, {{5, 6}, {7, 8}}}
//var a13 = [...][...][2]int{{{1, 2}, {3, 4}}, {{5, 6}, {7, 8}}} // 报错:invalid use of [...] array (outside a composite literal) 以及 missing type in composite literal
ad3 := [...][2][2]int{{{1, 2}, {3, 4}}, {{5, 6}, {7, 8}}}
//ad3x1 := [2][...][2]int{{{1, 2}, {3, 4}}, {{5, 6}, {7, 8}}} // 报错:invalid use of [...] array (outside a composite literal) 以及 missing type in composite literal
//ad3x2 := [2][2][...]int{{{1, 2}, {3, 4}}, {{5, 6}, {7, 8}}}// 报错:invalid use of [...] array (outside a composite literal)
//ad3x3 := [2][...][...]int{{{1, 2}, {3, 4}}, {{5, 6}, {7, 8}}}// 报错:invalid use of [...] array (outside a composite literal) 以及 missing type in composite literal
ad30 := new([2][2][2]int)
mfp.PrintFmtVal("a10", a10, verbs)
mfp.PrintFmtVal("a11", a11, verbs)
mfp.PrintFmtVal("a12", a12, verbs)
//mfp.PrintFmtVal("a13", a13, verbs)
mfp.PrintFmtVal("ad3", ad3, verbs)
//mfp.PrintFmtVal("ad3x1", ad3x1, verbs)
//mfp.PrintFmtVal("ad3x2", ad3x2, verbs)
//mfp.PrintFmtVal("ad3x3", ad3x3, verbs)
mfp.PrintFmtVal("ad30", ad30, verbs)
mfp.PrintFmtVal("*ad30", *ad30, verbs)
多维数组
二维数组
a6:     %T -> [3][3]int | %v -> [[1 2 3] [4 5 6] [7 8 9]] | %#v -> [3][3]int{[3]
int{1, 2, 3}, [3]int{4, 5, 6}, [3]int{7, 8, 9}}
a7:     %T -> [3][3]int | %v -> [[1 2 3] [4 5 6] [7 8 9]] | %#v -> [3][3]int{[3]
int{1, 2, 3}, [3]int{4, 5, 6}, [3]int{7, 8, 9}}
a8:     %T -> [3][3]int | %v -> [[1 2 3] [4 5 6] [7 8 9]] | %#v -> [3][3]int{[3]
int{1, 2, 3}, [3]int{4, 5, 6}, [3]int{7, 8, 9}}
ad2:    %T -> [3][3]int | %v -> [[1 2 3] [4 5 6] [7 8 9]] | %#v -> [3][3]int{[3]
int{1, 2, 3}, [3]int{4, 5, 6}, [3]int{7, 8, 9}}
ad20:   %T -> *[3][3]int | %v -> &[[0 0 0] [0 0 0] [0 0 0]] | %#v -> &[3][3]int{
[3]int{0, 0, 0}, [3]int{0, 0, 0}, [3]int{0, 0, 0}}
*ad20:  %T -> [3][3]int | %v -> [[0 0 0] [0 0 0] [0 0 0]] | %#v -> [3][3]int{[3]
int{0, 0, 0}, [3]int{0, 0, 0}, [3]int{0, 0, 0}}
三维数组
a10:    %T -> [2][2][2]int | %v -> [[[1 2] [3 4]] [[5 6] [7 8]]] | %#v -> [2][2]
[2]int{[2][2]int{[2]int{1, 2}, [2]int{3, 4}}, [2][2]int{[2]int{5, 6}, [2]int{7, 
8}}}
a11:    %T -> [2][2][2]int | %v -> [[[1 2] [3 4]] [[5 6] [7 8]]] | %#v -> [2][2]
[2]int{[2][2]int{[2]int{1, 2}, [2]int{3, 4}}, [2][2]int{[2]int{5, 6}, [2]int{7, 
8}}}
a12:    %T -> [2][2][2]int | %v -> [[[1 2] [3 4]] [[5 6] [7 8]]] | %#v -> [2][2]
[2]int{[2][2]int{[2]int{1, 2}, [2]int{3, 4}}, [2][2]int{[2]int{5, 6}, [2]int{7, 
8}}}
ad3:    %T -> [2][2][2]int | %v -> [[[1 2] [3 4]] [[5 6] [7 8]]] | %#v -> [2][2]
[2]int{[2][2]int{[2]int{1, 2}, [2]int{3, 4}}, [2][2]int{[2]int{5, 6}, [2]int{7, 
8}}}
ad30:   %T -> *[2][2][2]int | %v -> &[[[0 0] [0 0]] [[0 0] [0 0]]] | %#v -> &[2]
[2][2]int{[2][2]int{[2]int{0, 0}, [2]int{0, 0}}, [2][2]int{[2]int{0, 0}, [2]int{
0, 0}}}
*ad30:  %T -> [2][2][2]int | %v -> [[[0 0] [0 0]] [[0 0] [0 0]]] | %#v -> [2][2]
[2]int{[2][2]int{[2]int{0, 0}, [2]int{0, 0}}, [2][2]int{[2]int{0, 0}, [2]int{0, 
0}}}

U修改

修改元素

​ 根据以下代码和运行结果,我们可以发现在使用a[index]修改元素的时候,若编译时发现index已经超过a数组的长度,则编译时报错,若在运行时发现index已经超过a数组的长度,则程序引发panic。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
fmt.Println("一维数组")

a14 := [...]int{1, 2, 3}
mfp.PrintFmtVal("a14", a14, verbs)

a14[0] = 11
mfp.PrintFmtVal("a14", a14, verbs)

a14[len(a14)-1] = 33
mfp.PrintFmtVal("a14", a14, verbs)

//a14[len(a14)] = 44   // 报错:invalid argument: index 3 out of bounds [0:3]
//a14[len(a14)+1] = 55 // 报错:invalid argument: index 3 out of bounds [0:3]

pa141 := &a14[0]
*pa141 = 111
mfp.PrintFmtVal("a14", a14, verbs)
fmt.Println("二维数组")

a15 := [...][2]int{{1, 2}, {3, 4}}
a15[0][0] = 11
mfp.PrintFmtVal("a15", a15, verbs)

a15[len(a15)-1][0] = 33
mfp.PrintFmtVal("a15", a15, verbs)
//a15[len(a15)][0] = 11   // 报错:invalid argument: index 2 out of bounds [0:2]
//a15[len(a15)+1][0] = 11 // 报错:invalid argument: index 3 out of bounds [0:2]

pa151 := &a15[0][0]
*pa151 = 111
mfp.PrintFmtVal("a15", a15, verbs)
fmt.Println("三维数组和二维数组类似")
一维数组
a14:    %T -> [3]int | %v -> [1 2 3] | %#v -> [3]int{1, 2, 3}
a14:    %T -> [3]int | %v -> [11 2 3] | %#v -> [3]int{11, 2, 3}
a14:    %T -> [3]int | %v -> [11 2 33] | %#v -> [3]int{11, 2, 33}
a14:    %T -> [3]int | %v -> [111 2 33] | %#v -> [3]int{111, 2, 33}
二维数组
a15:    %T -> [2][2]int | %v -> [[11 2] [3 4]] | %#v -> [2][2]int{[2]int{11, 2},
 [2]int{3, 4}}
a15:    %T -> [2][2]int | %v -> [[11 2] [33 4]] | %#v -> [2][2]int{[2]int{11, 2}
, [2]int{33, 4}}
a15:    %T -> [2][2]int | %v -> [[111 2] [33 4]] | %#v -> [2][2]int{[2]int{111, 
2}, [2]int{33, 4}}
三维数组和二维数组类似
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
package main

import "fmt"

var a = [3]int{1, 2, 3}

func editA(i, v int) {
	a[i] = v
}

func main() {
	fmt.Println(a)
	editA(len(a), 4)
	fmt.Println(a)
}
panic: runtime error: index out of range [3] with length 3

用整个数组赋值

​ 根据以下代码和运行结果,我们可以发现在使用整个数组赋值的时候,若新数组的长度与原数组的长度不一致,或者新数组的元素类型与原数组的元素类型不一致,则编译时报错。

1
2
3
4
5
6
a16 := [...]int{1, 2, 3}
mfp.PrintFmtVal("a16", a16, verbs)
a16 = [...]int{2, 3, 4}
mfp.PrintFmtVal("赋值后 a16", a16, verbs)
//a16 = [...]int{2, 3, 4, 5} // 报错:cannot use [...]int{…} (value of type [4]int) as [3]int value in assignment
//a16 = [...]string{"a", "b", "c"} // 报错:cannot use [...]string{…} (value of type [3]string) as [3]int value in assignment	
a16:    %T -> [3]int | %v -> [1 2 3] | %#v -> [3]int{1, 2, 3}
赋值后 a16:    %T -> [3]int | %v -> [2 3 4] | %#v -> [3]int{2, 3, 4}

​ 可以看出,整个数组赋值时,新旧两个数组的元素个数(长度)和数组元素类型一定要都一致,否则将报错。

A访问

​ 访问数组中的某一元素,可通过索引下标,索引下标范围[0, len(数组名) - 1],即从0开始到数组的长度减去1。

直接访问指定索引下标的元素

1
2
3
4
5
a17 := [...]int{1, 2, 3}
fmt.Println("直接访问指定索引下标的元素")
fmt.Println(a17[0])
fmt.Println(a17[1])
fmt.Println(a17[len(a17)-1])
1
2
3

遍历数组

​ 通过遍历的方式访问所需索引下标或全部索引下标的元素:

1
2
3
4
5
6
7
8
9
for k, v := range a17 {
    if k%2 == 0 {
        fmt.Println(k, "->", v)
    }
}
mfp.PrintHr()
for k, v := range a17 {
    fmt.Println(k, "->", v)
}
0 -> 1
2 -> 3
------------------
0 -> 1
1 -> 2
2 -> 3

获取相关数组属性

1
2
3
a22 := [...]int{1, 2, 3}
fmt.Println("a22数组的长度 len(a22)=", len(a22))
fmt.Println("a22数组的容量 cap(a22)=", cap(a22))
a22数组的长度 len(a22)= 3
a22数组的容量 cap(a22)= 3

​ 我们会发现任何数组的长度和容量是相等的。

D删除

是否可以删除某一元素呢?

​ => 不可以

​ 通过上面的创建、修改、访问,我们知道数组有两个重要的属性:长度和元素类型。假设真能删除某一元素,那么新旧数组的长度就不一样了,这样就导致了前后两个数组不一致,故Go语言的设计中也没有提供删除数组元素的操作。

作为实参传递给函数或方法

​ 因数组在Go语言中是值类型,数组作为实参传递给函数,将发生完整复制数组,若数组很大,对于内存和性能将会是一个大开销。

其他问题

两个数组能进行比较吗?

​ 根据以下代码和运行结果,我们可以发现只有在两个数组的类型一致(数组元素类型和数组长度都一致)的情况下,可以使用==比较两个数组,但不可以使用><>=<=等比较符号进行比较,且在两个数组的元素值完全相同的情况下,==的结果才是true

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
a1 := [3]int{1, 2, 3}
//a2 := [4]int{1, 2, 3, 4}
a3 := [3]int{1, 2, 3}
//a4 := [3]string{"1", "2", "3"}
a5 := [3]int{2, 3, 4}
// 报错:invalid operation: a1 == a2 (mismatched types [3]int and [4]int)
//if a1 == a2 {
//	fmt.Println("a1 == a2")
//}

if a1 == a3 {
    fmt.Println("a1 == a3")
} else {
    fmt.Println("a1 != a3")
}

// 报错:invalid operation: a1 < a3 (operator < not defined on array)
//if a1 < a3 {
//	fmt.Println("a1 < a3")
//}

// 报错:invalid operation: a1 > a3 (operator > not defined on array)
//if a1 > a3 {
//	fmt.Println("a1 > a3")
//}

// 报错:invalid operation: a1 <= a3 (operator <= not defined on array)
//if a1 <= a3 {
//	fmt.Println("a1 <= a3")
//}

// 报错:invalid operation: a1 >= a3 (operator >= not defined on array)
//if a1 >= a3 {
//	fmt.Println("a1 >= a3")
//}

// 报错:invalid operation: a1 == a4 (mismatched types [3]int and [3]string)
//if a1 == a4 {
//	fmt.Println("a1 == a4")
//}

if a1 == a5 {
    fmt.Println("a1 == a5")
} else {
    fmt.Println("a1 != a5")
}
a1 == a3
a1 != a5

数组的元素类型可以是哪些?

​ 根据以下代码和运行结果,我们可以发现数组的元素类型可以任意类型,包括数组(即变成多维数组)。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
package main

import "github.com/before80/utils/mfp"

type St struct {
	a int
	b string
}

type Itf interface {
	M1()
	M2()
}

var verbs = []string{"T", "v", "#v"}

func main() {
	var aby [3]byte
	var abl [3]bool
	var as [3]string
	var ar [3]rune
	var autr [3]uintptr
	var ai8 [3]int8
	var ai16 [3]int16
	var ai32 [3]int32
	var ai64 [3]int64
	var ai [3]int
	var aui8 [3]uint8
	var aui16 [3]uint16
	var aui64 [3]uint64
	var aui32 [3]uint32
	var aui [3]uint
	var af32 [3]float32
	var af64 [3]float64
	var acplx64 [3]complex64
	var acplx128 [3]complex128
	var asli [3][]int
	var ast [3]St
	var aitf [3]Itf
	var af [3]func(int) int
	var am [3]map[string]int
	var ach [3]chan int
	mfp.PrintFmtVal("aby", aby, verbs)
	mfp.PrintFmtVal("abl", abl, verbs)
	mfp.PrintFmtVal("as", as, verbs)
	mfp.PrintFmtVal("ar", ar, verbs)
	mfp.PrintFmtVal("autr", autr, verbs)
	mfp.PrintFmtVal("ai8", ai8, verbs)
	mfp.PrintFmtVal("ai16", ai16, verbs)
	mfp.PrintFmtVal("ai32", ai32, verbs)
	mfp.PrintFmtVal("ai64", ai64, verbs)
	mfp.PrintFmtVal("ai", ai, verbs)
	mfp.PrintFmtVal("aui8", aui8, verbs)
	mfp.PrintFmtVal("aui16", aui16, verbs)
	mfp.PrintFmtVal("aui32", aui32, verbs)
	mfp.PrintFmtVal("aui64", aui64, verbs)
	mfp.PrintFmtVal("aui", aui, verbs)
	mfp.PrintFmtVal("af32", af32, verbs)
	mfp.PrintFmtVal("af64", af64, verbs)
	mfp.PrintFmtVal("acplx64", acplx64, verbs)
	mfp.PrintFmtVal("acplx128", acplx128, verbs)
	mfp.PrintFmtVal("asli", asli, verbs)
	mfp.PrintFmtVal("ast", ast, verbs)
	mfp.PrintFmtVal("asli", asli, verbs)
	mfp.PrintFmtVal("aitf", aitf, verbs)
	mfp.PrintFmtVal("af", af, verbs)
	mfp.PrintFmtVal("am", am, verbs)
	mfp.PrintFmtVal("ach", ach, verbs)
}
aby:    %T -> [3]uint8 | %v -> [0 0 0] | %#v -> [3]uint8{0x0, 0x0, 0x0}
abl:    %T -> [3]bool | %v -> [false false false] | %#v -> [3]bool{false, false, false}
as:     %T -> [3]string | %v -> [  ] | %#v -> [3]string{"", "", ""}
ar:     %T -> [3]int32 | %v -> [0 0 0] | %#v -> [3]int32{0, 0, 0}
autr:   %T -> [3]uintptr | %v -> [0 0 0] | %#v -> [3]uintptr{0x0, 0x0, 0x0}     
ai8:    %T -> [3]int8 | %v -> [0 0 0] | %#v -> [3]int8{0, 0, 0}
ai16:   %T -> [3]int16 | %v -> [0 0 0] | %#v -> [3]int16{0, 0, 0}
ai32:   %T -> [3]int32 | %v -> [0 0 0] | %#v -> [3]int32{0, 0, 0}
ai64:   %T -> [3]int64 | %v -> [0 0 0] | %#v -> [3]int64{0, 0, 0}
ai:     %T -> [3]int | %v -> [0 0 0] | %#v -> [3]int{0, 0, 0}
aui8:   %T -> [3]uint8 | %v -> [0 0 0] | %#v -> [3]uint8{0x0, 0x0, 0x0}
aui16:  %T -> [3]uint16 | %v -> [0 0 0] | %#v -> [3]uint16{0x0, 0x0, 0x0}       
aui32:  %T -> [3]uint32 | %v -> [0 0 0] | %#v -> [3]uint32{0x0, 0x0, 0x0}       
aui64:  %T -> [3]uint64 | %v -> [0 0 0] | %#v -> [3]uint64{0x0, 0x0, 0x0}       
aui:    %T -> [3]uint | %v -> [0 0 0] | %#v -> [3]uint{0x0, 0x0, 0x0}
af32:   %T -> [3]float32 | %v -> [0 0 0] | %#v -> [3]float32{0, 0, 0}
af64:   %T -> [3]float64 | %v -> [0 0 0] | %#v -> [3]float64{0, 0, 0}
acplx64:        %T -> [3]complex64 | %v -> [(0+0i) (0+0i) (0+0i)] | %#v -> [3]co
mplex64{(0+0i), (0+0i), (0+0i)}
acplx128:       %T -> [3]complex128 | %v -> [(0+0i) (0+0i) (0+0i)] | %#v -> [3]c
omplex128{(0+0i), (0+0i), (0+0i)}
asli:   %T -> [3][]int | %v -> [[] [] []] | %#v -> [3][]int{[]int(nil), []int(nil), []int(nil)}
ast:    %T -> [3]main.St | %v -> [{0 } {0 } {0 }] | %#v -> [3]main.St{main.St{a:0, b:""}, main.St{a:0, b:""}, main.St{a:0, b:""}}
asli:   %T -> [3][]int | %v -> [[] [] []] | %#v -> [3][]int{[]int(nil), []int(nil), []int(nil)}
aitf:   %T -> [3]main.Itf | %v -> [<nil> <nil> <nil>] | %#v -> [3]main.Itf{main.Itf(nil), main.Itf(nil), main.Itf(nil)}
af:     %T -> [3]func(int) int | %v -> [<nil> <nil> <nil>] | %#v -> [3]func(int)
 int{(func(int) int)(nil), (func(int) int)(nil), (func(int) int)(nil)}
am:     %T -> [3]map[string]int | %v -> [map[] map[] map[]] | %#v -> [3]map[stri
ng]int{map[string]int(nil), map[string]int(nil), map[string]int(nil)}
ach:    %T -> [3]chan int | %v -> [<nil> <nil> <nil>] | %#v -> [3]chan int{(chan int)(nil), (chan int)(nil), (chan int)(nil)}

可以对数组进行cap()操作?

1
2
3
4
5
6
7
8
9
package main

import "fmt"

func main() {
	arr := [...]int{0, 1, 2, 3, 4, 5}
	fmt.Println(len(arr)) // 6
	fmt.Println(cap(arr)) // 6
}

​ 可见,可以对数组进行cap()操作,且数组的 容量和长度 是一致的!

数组的长度是固定的,那是否可以作为常量的值?

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
package main

import "fmt"

var arr = [3]int{1, 2, 3}

const LEN = len(arr)

func main() {
	fmt.Println(LEN) // 3
}

​ 可见,数组的长度是可以作为常量的值的!

易混淆的知识点

数组指针和指针数组

​ 根据以下代码和运行结果,我们可以发现对数组指针进行赋值时,若&a所在的数组与ptr数组指针在定义时所指向的数组类型不同,则编译时报错。

​ 数组指针和指针数组,怎么区分呢,直接看最后两字是什么!

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
fmt.Println("数组指针")
a18 := [...]int{1, 2, 3}
a19 := [...]int{1, 2, 3, 4}
_ = a19
var ptrA181 *[3]int
ptrA181 = &a18
mfp.PrintFmtVal("ptrA181", ptrA181, []string{"T", "v", "#v"})
mfp.PrintFmtVal("*ptrA181", *ptrA181, []string{"T", "v", "#v"})
//ptrA181 = &a19 // 报错:cannot use &a19 (value of type *[4]int) as *[3]int value in assignment

mfp.PrintHr()
fmt.Println("指针数组")
xa201, xa202, xa203 := 1, 2, 3
a20 := [...]*int{&xa201, &xa202, &xa203}
mfp.PrintFmtVal("a20", a20, []string{"T", "v", "#v"})
for k, v := range a20 {
    fmt.Println(k, "->", *v)
}
数组指针
ptrA181:        %T -> *[3]int | %v -> &[1 2 3] | %#v -> &[3]int{1, 2, 3}
*ptrA181:       %T -> [3]int | %v -> [1 2 3] | %#v -> [3]int{1, 2, 3}
------------------
指针数组
a20:    %T -> [3]*int | %v -> [0xc000012340 0xc000012348 0xc000012350] | %#v -> [3]*int{(*int)(0xc000012340), (*int)(0xc000012348), (*int)(0xc000012350)}
0 -> 1
1 -> 2
2 -> 3

对数组指针进行for range遍历

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package main

import "fmt"

func main() {
	a := [3]int{1, 2, 3}
	p := &a

	// 遍历数组指针
	for i, v := range p {
		fmt.Println(i, v)
	}

	// 遍历数组
	for i, v := range *p {
		fmt.Println(i, v)
	}
}

Output:
0 1
1 2
2 3
0 1
1 2
2 3

易错点

访问最后一个数组元素

​ 直接用a[len(a)]访问数组a的最后一个元素 =》肯定报错

1
2
3
4
fmt.Println("访问数组的最后一个元素")
a21 := [...]int{1, 2, 3}
//fmt.Println(a21[len(a21)]) // 报错:invalid argument: index 3 out of bounds [0:3]
fmt.Println(a21[len(a21)-1]) // 正确方式
3

以为[...]T可以用来作为形参

1
2
3
4
5
6
7
8
package main

func editA1(a [...]int) {
	_ = a
}

func main() {
}

​ 然而,编译时直接报错:

1
syntax error: unexpected ..., expected expression

以为数组的零值是nil

数组的特点

​ 数组中的元素在内存中的存储是连续的,故检索数组非常快,但定义后数组的大小不能再修改。

最后修改 October 10, 2024: 更新 (a4b8f85)