《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 }
运行结果如下
其它类型待完善