复杂数据类型-数组array
# 1. 数组基本使用
# 介绍
数组是一个由固定长度的特定类型元素组成的序列,一个数组可以由零个或多个元素组成。因为数组的长度是固定的,所以在Go语言中很少直接使用数组。
和数组对应的类型是 Slice(切片),Slice 是可以增长和收缩的动态序列,功能也更灵活,但是想要理解 slice 工作原理的话需要先理解数组,所以本节主要为大家讲解数组的使用,至于 Slice(切片)将在《Go语言切片 (opens new window)》一节中为大家讲解。
数组使用步骤:
- 声明数组
- 给数组元素赋值
- 使用数组
- 数组索引从0开始,且不得越界否则panic
- Go数组是值类型,变量传递默认是值传递,因此会进行值拷贝
- 修改原本的数组,可以使用引用传递(指针)
# Go语言数组的声明
数组的声明语法如下:
var 数组变量名 [元素数量]Type
1
语法说明如下所示:
- 数组变量名:数组声明及使用时的变量名。
- 元素数量:数组的元素数量,可以是一个表达式,但最终通过编译期计算的结果必须是整型数值,元素数量不能含有到运行时才能确认大小的数值。
- Type:可以是任意基本类型,包括数组本身,类型为数组本身时,可以实现多维数组。
package main
import "fmt"
func main() {
//第零种:未设置初始值会根据数组类型自动赋予默认值,比如int默认值就是0 [0 0 0]
var arr0 [3]int
fmt.Println(arr0)
//第一种:
var arr1 [3]int = [3]int{3, 6, 9}
fmt.Println(arr1)
//第二种:
var arr2 = [3]int{1, 4, 7}
fmt.Println(arr2)
//第三种:在数组的定义中,如果在数组长度的位置出现“...”省略号,则表示数组的长度是根据初始化值的个数来计算
var arr3 = [...]int{4, 5, 6, 7}
fmt.Println(arr3)
//第四种:按照索引初始化元素
var arr4 = [...]int{2: 66, 0: 33, 1: 99, 3: 88}
fmt.Println(arr4)
//第四种:结构体类型数组
var arr5 = [...]struct {
name string
age int
}{
{"王麻子", 10},
{"吕秀才", 29},
}
fmt.Println(arr5)
}
/*
[0 0 0]
[3 6 9]
[1 4 7]
[4 5 6 7]
[33 99 66 88]
[{王麻子 10} {吕秀才 29}]
*/
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
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
# 注意点
数组的长度是数组类型的一个组成部分,因此 [3]int 和 [4]int 是两种不同的数组类型,数组的长度必须是常量表达式,因为数组的长度需要在编译阶段确定。
q := [3]int{1, 2, 3}
q = [4]int{1, 2, 3, 4} // 编译错误:无法将 [4]int 赋给 [3]int
1
2
2
# 访问数组元素
数组的每个元素都可以通过索引下标来访问,索引下标的范围是从 0 开始到数组长度减 1 的位置,内置函数 len() 可以返回数组中元素的个数。
# 普通for循环
# for-range
package main
import "fmt"
func main() {
//实现的功能:请输入学生的成绩,并输出学生的成绩,求出成绩的总和,平均数:
var scores [5]int
for i := 0; i < len(scores); i++ {
fmt.Printf("请输入学生%d的成绩", i)
scores[i] = i * 5
//fmt.Scanln(&scores[i])
}
// 普通for循环
for j := 0; j < len(scores); j++ {
fmt.Printf("学生的编号%d - 成绩是%d\\n", j+1, scores[j])
}
// 键值循环 for-range
for key, value := range scores {
fmt.Printf("学生的编号%d - 成绩是%d\\n", key+1, value)
}
}
/*
请输入学生0的成绩请输入学生1的成绩请输入学生2的成绩请输入学生3的成绩请输入学生4
的成绩学生的编号1 - 成绩是0
学生的编号2 - 成绩是5
学生的编号3 - 成绩是10
学生的编号4 - 成绩是15
学生的编号5 - 成绩是20
学生的编号1 - 成绩是0
学生的编号2 - 成绩是5
学生的编号3 - 成绩是10
学生的编号4 - 成绩是15
学生的编号5 - 成绩是20
*/
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
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
# 修改原数组(使用指针)
package main
import (
"fmt"
)
// 函数接收值类型,默认有值拷贝
func test(arr [3]int) {
arr[0] = 66
}
// 函数修改原本数组,需要使用引用传递
func test2(arr *[3]int) {
(*arr)[0] = 66 //可以缩写arr[0]=66 编译器自动识别,arr是指针类型
}
func main() {
//声明arr数组,需要考虑传递函数参数时,数组的长度一致性
arr := [3]int{11, 22, 33}
//test函数不会修改数组
test(arr)
fmt.Println(arr)
//test2修改了数组
test2(&arr)
fmt.Println(arr)
}
/*
[11 22 33]
[66 22 33]
*/
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
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
# 2. 数组内存分析
# 普通数组内存分析
package main
import "fmt"
func main() {
//声明数组:
var arr [3]int16
//获取数组的长度:
fmt.Println(len(arr))
//打印数组:
fmt.Println(arr) //[0 0 0]
//证明arr中存储的是地址值:
fmt.Printf("arr的地址为:%p", &arr)
//第一个空间的地址:
fmt.Printf("arr的地址为:%p", &arr[0])
//第二个空间的地址:
fmt.Printf("arr的地址为:%p", &arr[1])
//第三个空间的地址:
fmt.Printf("arr的地址为:%p", &arr[2])
}
/*
3
[0 0 0]
arr的地址为:0xc0000140c8arr的地址为:0xc0000140c8arr的地址为:0xc0000140caarr的地址为:0xc0000140cc
*/
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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# 注意点
数组每个空间占用的字节数取决于数组类型(比如int16所在字节为2,内存地址相应的也会发生变化),需要注意的是拿取第一个当作数组的初始内存地址
# 赋值内存:(数组是值类型,在栈中开辟内存)
# 3. 多维数组
# 介绍
Go语言中允许使用多维数组,因为数组属于值类型,所以多维数组的所有维度都会在创建时自动初始化零值,多维数组尤其适合管理具有父子关系或者与坐标系相关联的数据。
声明多维数组的语法如下所示:
var array_name [size1][size2]...[sizen] array_type
1
其中,array_name 为数组的名字,array_type 为数组的类型,size1、size2 等等为数组每一维度的长度。
# 多维数组的声明
package main
import "fmt"
func main() {
//第零种:未设置初始值会根据数组类型自动赋予默认值,比如int默认值就是0 [0 0 0]
var arr0 [2][3]int
fmt.Println(arr0)
//第一种:
var arr1 [2][3]int = [2][3]int{{3, 6, 9}, {3, 6, 9}}
fmt.Println(arr1)
//第二种:
var arr2 = [2][3]int{{3, 6, 9}, {3, 6, 19}}
fmt.Println(arr2)
//第三种:在数组的定义中,如果在数组长度的位置出现“...”省略号,则表示数组的长度是根据初始化值的个数来计算
var arr3 = [...][3]int{{3, 6, 9}, {3, 6, 9}}
fmt.Println(arr3)
//第四种:按照索引初始化元素
var arr4 = [...][2]int{{0: 33, 1: 99}, {1: 33, 0: 99}}
fmt.Println(arr4)
//第四种:结构体类型数组
var arr5 = [2][2]struct {
name string
age int
}{
{{"王麻子", 10}, {"吕秀才", 29}},
{{"王麻子1", 10}, {"吕秀才2", 29}},
}
fmt.Println(arr5)
}
/*
[[0 0 0] [0 0 0]]
[[3 6 9] [3 6 9]]
[[3 6 9] [3 6 19]]
[[3 6 9] [3 6 9]]
[[33 99] [99 33]]
[[{王麻子 10} {吕秀才 29}] [{王麻子1 10} {吕秀才2 29}]]
*/
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
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
# 二维数组内存说明
# 二维数组赋值操作内存说明
# 二维数组的遍历
package main
import "fmt"
func main() {
// 定义二维数组
var arr [2][3]int = [2][3]int{{2, 3, 4}, {5, 6, 7}}
fmt.Println(arr)
// 普通for循环
for i := 0; i < len(arr); i++ {
for j := 0; j < len(arr[i]); j++ {
fmt.Print(arr[i][j], "\\t")
}
fmt.Println()
}
// 键值循环 for-range
for _, idxValue := range arr {
for _, idxValue2 := range idxValue {
fmt.Print(idxValue2, "\\t")
}
fmt.Println()
}
}
/*
[[2 3 4] [5 6 7]]
2 3 4
5 6 7
2 3 4
5 6 7
*/
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
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
# 4. 数组注意点
# 1. 数组的长度是数组类型的一个组成部分,因此 [3]int 和 [4]int 是两种不同的数组类型,数组的长度必须是常量表达式,因为数组的长度需要在编译阶段确定。
q := [3]int{1, 2, 3}
q = [4]int{1, 2, 3, 4} // 编译错误:无法将 [4]int 赋给 [3]int
1
2
2
# 2. Go中数组属值类型,在默认情况下是值传递,因此会进行值拷贝
# 3. 在其它函数中,去修改原来的数组,可以使用引用传递(指针方式)。
# 4. 数组是多个相同类型数据的组合,且长度固定,无法扩容
编辑 (opens new window)