《Go程序设计语言》学习笔记之数组
《Go程序设计语言》学习笔记之数组
一. 环境
Centos8.5, go1.17.5 linux/amd64
二. 概念
数组是具有固定长度且拥有零个或多个相同数据类型元素的序列。
三. 声明
声明一个数组a,然后打印数组、数组a的长度、数组a的类型。从打印的a的类型中可以看出数组的长度是类型的一部分。
// test sample
package main
import (
"fmt"
)
func main() {
var a [3]int
fmt.Printf("a: %d\n", a)
fmt.Printf("len: %d\n", len(a))
fmt.Printf("type: %T\n", a)
}
运行结果如下
四. 初始化
声明与初始化个人感觉是C/C++中的说法,严格来说在Go中不太严谨。在Go中,定义的变量,如果没有显式初始化的话,变量会默认初始化。也就是说,声明即是初始化。Go中有个零值机制。零值机制保障所有的变量是良好定义的,Go里面不存在未初始化变量。
下面示例了4种初始化的方式
第一种,声明了一个长度为3的整型数组a,从打印结果来看, 每个元素初始值为零值。
第二种,声明了一个长度为3的整型数组b,使用数组字面量初始化一个数组。字面量数组中只有两个元素,但是数组b的长度为3,最后一个元素的初始值为零值。
第三种,使用短变量声明的形式,使用数组字面量来初始化整型数组c,数组字面量中的长度是”...“,则数组的长度由初始化数组的元素个数决定。
第四种,先使用常量计数器iota声明一组常量值作为下标,然后将下标与对应位置上的元素的值对应起来。这种的方式好处就是索引可以按照任意顺序出现。
8 func main() {
9 // init way1, zero value
10 var a [3]int
11 for _, v := range a {
12 fmt.Printf("%d\t", v)
13 }
14 fmt.Printf("\n")
15
16 // init way2
17 fmt.Println("----------")
18 var b [3]int = [3]int{1, 2}
19 for _, v := range b {
20 fmt.Printf("%d\t", v)
21 }
22 fmt.Printf("\n")
23
24 // init way3
25 fmt.Println("----------")
26 c := [...]int{4, 5, 6}
27 for _, v := range c {
28 fmt.Printf("%d\t", v)
29 }
30 fmt.Printf("\n")
31
32 // init way4
33 fmt.Println("----------")
34 type Currency int
35
36 const (
37 USD Currency = iota
38 EUR
39 GBP
40 RMB
41 )
42
43 symbol := [...]string{USD: "$", EUR: "€", GBP: "£", RMB: "¥"}
44 for _, v := range symbol {
45 fmt.Printf("%s\t", v)
46 }
47 fmt.Printf("\n")
48 }
运行结果如下
五. 访问
数组中的元素可通过下标进行访问
8 func main() {
9 arr := [3]string{"China", "America", "Japan"}
10 fmt.Printf("%s\n", arr[0])
11 fmt.Printf("%s\n", arr[1])
12 fmt.Printf("%s\n", arr[2])
13 }
运行结果如下
六. 使用
1.变量
作变量使用,这个没什么好说的了。
2.修改元素的值
1) 通过下标指定元素,对指定的元素进行修改
8 func main() {
9 a1 := [...]int{1, 2, 3}
10
11 for i, _ := range a1 {
12 a1[i] += 4
13 }
14
15 fmt.Printf("%d %d %d\n", a1[0], a1[1], a1[2])
16 }
运行结果如下
2) 笔者用过的错误的修改方式,有些想当然了。
Go中基本是值语义的,即是值传递的
for循环中,v是数组中元素的一个副本,对副本的修改不会对原始元素产生影响
8 func main() {
9 a1 := [...]int{1, 2, 3}
10
11 for _, v := range a1 {
12 v += 4
13 }
14
15 fmt.Printf("%d %d %d\n", a1[0], a1[1], a1[2])
16 }
运行结果如下,并未修改成功。
3.比较
如果一个数组的元素类型是可比较的,那这个数组也是可比较的。
8 func main() {
9 a1 := [...]int{1, 2, 3}
10 a2 := [...]int{1, 2, 4}
11 a3 := [3]int{1, 2, 3}
12 fmt.Printf("%t %t %t\n", a1 == a2, a1 == a3, a2 == a3)
13 }
运行结果如下
若两个数组的类型不一致,则不允许进行比较
14 a4 := [4]int{1, 2, 3, 4}
15 fmt.Printf("%t\n", a1 == a4)
编译时报错如下,提示无效操作
invalid operation: a1 == a4 (mismatched types [3]int and [4]int)
4.作函数参数
Go中,数组是值传递的。一般是传递一个数组的指针,这样有两个好处,一是对于较大的数组,效率较高; 二是可以对原数组进行修改。下面示例两种传参方式
1) 值传递,在被调用函数 modifyArrayElement 中,通过打印结果可以看到是修改成功了,但是这只是对传入的数组的副本进行了修改,对原始数组并未产生影响。
8 func modifyArrayElement(array [5]int) {
9 array[0] += 10
10 array[1] += 10
11 array[2] += 10
12 array[3] += 10
13 array[4] += 10
14
15 fmt.Println("...in function...")
16 for _, v := range array {
17 fmt.Println(v)
18 }
19 fmt.Println("...in function...")
20 }
21
22 func main() {
23 a1 := [...]int{1, 2, 3, 4, 5}
24 fmt.Println(a1)
25
26 modifyArrayElement(a1)
27 fmt.Println(a1)
28 }
运行结果如下
2) 指针传递,在被调用函数 modifyArrayElement 的参数中,传入的是长度为5的数组的指针,通过指针可以对原数组进行修改。代码第9行和第10行array前的解引用符号"*"可以省略,可进行隐式转化。
8 func modifyArrayElement(array *[5]int) {
9 for i, _ := range *array {
10 (*array)[i] += 10
11 }
12 }
13
14 func main() {
15 a1 := [...]int{1, 2, 3, 4, 5}
16 fmt.Println(a1)
17
18 modifyArrayElement(&a1)
19 fmt.Println(a1)
20 }
运行结果如下
5.赋值
可以将一个数组赋值给另一个数组
1) 将数组b赋值给数组a
8 func main() {
9 a := [...]int{1, 2, 3}
10 fmt.Println(a)
11 b := [3]int{4, 5, 6}
12
13 a = b
14 fmt.Println(a)
15 }
16
运行结果如下
2) 通过清零函数zero将传入的数组清零,对传入的数组指针进行解引用,然后对数组进行赋值,完成清零操作。
8 func zero(array *[5]int) {
9 *array = [5]int{}
10 }
11
12 func main() {
13 a := [...]int{1, 2, 3, 4, 5}
14 fmt.Println(a)
15
16 zero(&a)
17 fmt.Println(a)
18 }
运行结果如下
4.与slice结合使用
具体参考slice一文
七. 注意
1) 适用场景
适用于固定长度的序列,如使用SHA256加密散列生成的摘要,其长度为256位,即[32]byte。
2) 越界
在访问或修改数组中的元素时,注意越界的问题
示例代码
8 func main() {
9 a := [...]int{1, 2, 3, 4, 5}
10
11 fmt.Println(a)
12 fmt.Println(a[5])
13 }
编译时,提示无效的数组索引5
八.疑问
数组中的元素可以是哪些类型?
1) 基本类型
2) 数组类型
8 func main() {
9 // element type: int
10 a1 := [...]int{1, 2, 3, 4, 5}
11 a11 := [...]int{11, 22, 33, 44, 55}
12 a111 := [...]int{11, 22, 33, 44, 55}
13
14 // element type: string
15 a2 := [...]string{"aa", "bb", "cc", "dd", "ee"}
16
17 // element type: bool
18 a3 := [5]bool{true, false, false, false, false}
19
20 // element type: array
21 a4 := [3][5]int{a1, a11}
22
23 fmt.Println(a1)
24 fmt.Println(a11)
25 fmt.Println(a111)
26
27 fmt.Println("----------")
28 fmt.Println(a2)
29 fmt.Println(a3)
30 fmt.Println(a4)
31 }
运行结果如下
其它类型待完善