Go语言实践[回顾]教程18--详解Go语言复合数据类型之数组 [...]
数组,顾名思义就是数据的组合,但必须是相同类型数据。Go 语言的数组是一个由固定长度(元素个数,零个或多个)的相同唯一类型元素(数据项)组成的序列,元素的类型可以是任意的原始类型和自定义类型,且这些元素已经按照在数组中的位置进行了自动索引编号。因 Go 语言数组不支持动态创建,长度固定,所以更适合原始预置类数据的定义,需要有足够动态特性的请使用后面章节介绍的切片。
一维数组
数组元素不再是数组的数组,只有一层数组结构,称之为一维数组。也是最常用最基本的数组形式。
一维数组的声明及初始化
声明数组需要指定元素个数和元素类型,完整声明语法格式如下:
var 变量名 [长度]元素数据类型
● 变量名:声明的数组变量的名称,符合语法规则的任意名字。
● 长度:元素个数,也称之为数组大小,表示声明的这个数组有多少个元素,必须是整数。
● 元素数据类型:数组内元素的数据类型,可以是任何基本类型、自定义类型,也可以是数组(但就成了多维数组)。
// test01 项目的 main 包,文件名 main.go
package main
import (
"fmt"
)
// 主函数,程序入口
func main() {
var a [5]int // 声明有5个元素的 int 数组,所有元素初始化为 0
var b [4]string // 声明有4个元素的 string 数组,所以元素初始化为空字符串
var c = [2]float32{12.1, 23.6} // 声明有2个元素的 float32 数组,初始化元素分别为 12.1、23.6
d := [2]string{"abc", "efg"} // 声明有2个元素的 string 数组,初始化元素分别为 “abc” 和 “efg”
e := [5]int{56, 39} // 声明有5个元素的 int 数组,初始化第1、2个元素分别为 56、39,其他元素为 0
f := [5]int{2: 56, 3: 39} // 声明有5个元素的 int 数组,初始化第2、3个元素分别为 56、39,其他元素为 0
g := [...]int{56, 39} // 声明 int 数组,初始化元素分别为 56、39,数组长度是编译器推导出来的有2个元素
fmt.Println(a)
fmt.Println(b)
fmt.Println(c)
fmt.Println(d)
fmt.Println(e)
fmt.Println(f)
fmt.Println(g)
}
第10、11行,完整格式声明,只声明没有赋值,会自动初始化为元素类型的零值,所以 int 类型的各元素被初始化为 0,string 类型的被初始化为空字符串。
第12行,完整格式声明,并初始化各元素的值。声明有 2 个元素就在类型后面的花括号内写几个值,中间用逗号隔开。
第13~16行,都是在声明局部变量时使用的格式,编译器根据元素值的类型自动推导出类型。
第14行,声明的是有 5 个元素,但是花括号内只有两个值,那就是代表这是前两个的值,后面剩余的就是类型的零值。声明的是 int 类型,那其余元素就是 0 值。
第15行,同样是声明了5个元素,但花括号只有两个值。注意这两个值是定义了索引号的,数组的索引号是从 0 开始的,所以 2: 56 是表示 2 号元素为 56,3: 39 是表示 3 号元素为 39。那么剩下的 0号、1号、4号 三个元素就是 0 了。
第16行,使用 … 表示不提前声明数量,有初始化的元素数量决定,这里编译器会推导出是有两个元素的 int 数组。
上述代码编译运行结果如下:
[0 0 0 0 0]
[ ]
[12.1 23.6]
[abc efg]
[56 39 0 0 0]
[0 0 56 39 0]
[56 39]
访问一维数组的元素
对数组元素的访问是通过方括号加下标(索引号、位置)来进行的,索引号是从 0 开始,具体见如下示例:
// test01 项目的 main 包,文件名 main.go
package main
import (
"fmt"
)
// 主函数,程序入口
func main() {
arr := [...]int{10, 56, 39}
fmt.Println(arr) // 打印输出 arr 整个数组
fmt.Println(arr[0]) // 打印输出数组 arr 的 0 号元素(第 1 个元素)
fmt.Println(arr[2]) // 打印输出数组 arr 的 2 号元素(第 3 个元素)
arr[0] = 101 // 将 arr 的 0 号元素赋值为 101
arr[2] = 103 // 将 arr 的 2 号元素赋值为 103
fmt.Println(arr) // 打印输出 arr 整个数组
}
上述代码编译运行结果如下:
[10 56 39]
10
39
[101 56 103]
获取一维数组的长度
如何获取数组的长度(元素个数),使用 Go 语言内置的函数 len() 即可:
arr := [3]int
n := len(arr) // 此时变量 n 等于 3,为 int 类型
数组的比较判断
数组也是可以通过 ==、!= 进行比较判断的,但是必须是同长度同类型的才可以比较,否则会报错。应为长度也是数组的一部分,所以长度不同的两个数组,不属于完全相同的两个类型。
// test01 项目的 main 包,文件名 main.go
package main
import (
"fmt"
)
// 主函数,程序入口
func main() {
a1 := [3]int{10, 56, 39}
a2 := [3]int{10, 56, 39}
a3 := [3]int{82, 56, 39}
//a4 := [2]int{10, 56}
//a3 := [2]string{"ab", "cd"}
fmt.Println(a1 == a2)
fmt.Println(a1 == a3)
//fmt.Println(a1 == a4)
//fmt.Println(a4 == a5)
}
上述代码编译运行结果如下:
true
false
上述代码如果放开注释,那么最后两行代码就会报错,因为它们之间长度或类型不一致,是无法比较的。
一维数组的遍历
数组的遍历就是依次获取数组中所有的元素,有两个方法,一个是使用 for 计数循环,一个是使用 for range 循环:
// test01 项目的 main 包,文件名 main.go
package main
import (
"fmt"
)
// 主函数,程序入口
func main() {
arr := [...]int{10, 56, 39}
fmt.Println("使用 for 循环计数方法遍历")
// 遍历数组的方法一
n := len(arr)
for i := 0; i < n; i++ {
fmt.Println("索引:", i, ",值:", arr[i])
}
fmt.Println("使用 for rande方法遍历")
// 遍历数组的方法二
for k, v := range arr {
fmt.Println("索引:", k, ",值:", v)
}
// 遍历数组的方法二(只用值不用索引)
for _, v := range arr {
fmt.Println("值:", v)
}
}
上述代码编译运行结果如下:
使用 for 循环计数方法遍历
索引: 0 ,值: 10
索引: 1 ,值: 56
索引: 2 ,值: 39
使用 for rande方法遍历
索引: 0 ,值: 10
索引: 1 ,值: 56
索引: 2 ,值: 39
值: 10
值: 56
值: 39
遍历的方法一是要首先得到数组的长度(第15行),然后定义 for 循环的循环次数。循环计数变量初始化为 0,刚好与数组的第一个元素的索引号相同。接下来循环变量 i 是递增的,用 i 做取数组元素值的下标,就依次取出每个元素的值了。而 i 的值就刚好是索引号。
遍历的方法二没有使用循环计数变量,而是使用了 range 关键字,将循环次数自动限定为其后面的数组长度,然后从0号索引位置开始,依次递增循环。每次循环都会返回当前的索引号和元素值,k 和 v就是分别接收这两个数据的。第一个是索引号,第二个是元素值。
在某些应用场景下,我们可能用不到索引号,只需要元素值就可以了。如果这个时候我们要使用方法二进行遍历该如何接两个返回值呢?如果我们正常接了,但是又没有使用 k,那么编译时会报错。这种情况就该占位标识符 “_” 登场了,使用下划线占位原来 k 的位置,这样接到的值就会直接被抛弃,不会要求后面必须使用。所有有了最后的那段代码。
如果使用 for range 方法只要循环索引号,将第28行代码中 := 左侧的两个变量改成只有一个变量,那么这个变量接的就是索引号,就没有元素值传出来了。
二维(多维)数组
一个数组的元素还是个数组,而元素数组的元素不再是数组的数组,有两层数组结构,称之为二维数组。那么有这类三层数组结构的就叫三维数组,依次类推。我们通常将这些不只有一层数组结构的数组统称多维数组。了解了二维数组的,那么其他多维数组就可以触类旁通了。
二维数组的声明、初始化、元素访问
上面了解了一维数组的基本结构和概念,那么对二维数组就很容易理解了,就是一维数组的镶嵌叠加,基本特性与一维数组相同。这里直接上演示代码:
// test01 项目的 main 包,文件名 main.go
package main
import (
"fmt"
)
// 主函数,程序入口
func main() {
var arr1 [2][2]int // 声明一个二维数组,第一维有两个元素,第二维有两个元素,没有赋值默认最终元素值是 0
arr2 := [3][2]int{ // 声明一个二维数组,第一维有三个元素,但只给了两个值
{10, 56}, // 没有索引号,就默认从 0 号索引开始排列依次赋值
2: {72, 31}, // 有索引号的,按照索引位置赋值
}
fmt.Println("数组 arr1:", arr1)
fmt.Println("数组 arr2:", arr2)
fmt.Println("arr2第一个元素:", arr2[0])
fmt.Println("arr2第一个元素内的第二个元素:", arr2[0][1])
arr2[0][1] = 99 // 将 arr2 第一个元素里面的第二个元素的值修改为 99
fmt.Println("修改后的数组 arr2:", arr2)
arr1[1] = [2]int{66, 87} // 将 arr1 第二个元素整体赋值一个新的数组格式的数据
fmt.Println("修改后的数组 arr1:", arr1)
}
上述代码编译运行结果如下:
数组 arr1: [[0 0] [0 0]]
数组 arr2: [[10 56] [0 0] [72 31]]
arr2第一个元素: [10 56]
arr2第一个元素内的第二个元素: 56
修改后的数组 arr2: [[10 99] [0 0] [72 31]]
修改后的数组 arr1: [[0 0] [66 87]]
**从结果就可以看出,二维数组就是等于一维数组的元素又是一个一维数组。**所以这里就不再过多描述了,如果理解了上面的一维数组,再看这段代码就很容易理解二维数组了。
获取二维数组的长度
二维数组有两个长度,及第一维有几个元素,第二维(第一维的元素)有几个元素,同样都可以使用 len() 内置函数获取到:
n1 := len(arr2) // 放到上例代码中,n1 的值就是 3
n2 := len(arr2[0]) // 放到上例代码中,n2 的值就是 2
二维数组的遍历
二维数组的遍历方法与一维数组原理相同。只是因为多了一层数组,若要遍历第二维的元素,那么循环内就要嵌套一个循环,可使用的循环方法与一维数组相同。下面用 for range 演示遍历过程:
// test01 项目的 main 包,文件名 main.go
package main
import (
"fmt"
)
// 主函数,程序入口
func main() {
arr := [...][2]int{
{10, 56},
{72, 31},
}
fmt.Println("数组 arr:", arr)
for k1, v1 := range arr {
for k2, v2 := range v1 {
fmt.Println(k1, "->", k2, ":", v2)
}
}
}
上述代码编译运行结果如下:
数组 arr: [[10 56] [72 31]]
0 -> 0 : 10
0 -> 1 : 56
1 -> 0 : 72
1 -> 1 : 31
在第18行,因为 v1 是数组 arr 第一维的元素,所以它还是个数组,那就可以继续使用 for range 遍历。
注意,Go语言的数组是不支持动态增加和删除元素的,有此需求需要使用后面章节介绍的切片。
.
.
上一节:Go/Golang语言学习实践[回顾]教程17–详解Go语言复合数据类型之指针 Pointer