Go 语言基础之数组
数组定义
Go 语言中定义数组的格式如下:
var 数组名称 [数组长度]数组每一项数据的类型
比如要定义一个长度为 3 的整数类型数组:
var arr [3]int
注意在 Go 语言中,数组的类型是由数组长度和数据类型决定的,即 [3]int
和 [5]int
是不同的类型,另外数组长度一经定义后就不可以修改了,数组长度是一个常量。
当数组定义后而没有赋值,则会根据类型而赋默认值,比如整数或浮点数类型默认值是 0
,字符串类型默认值是 ''
,布尔类型默认值是 false
等:
func main() {
var arr1 [3]int
var arr2 [3]float64
var arr3 [3]string
var arr4 [3]bool
fmt.Println(arr1) // [0 0 0]
fmt.Println(arr2) // [0 0 0]
fmt.Println(arr3) // [ ]
fmt.Println(arr4) // [false false false]
}
如果要给数组赋值,所有值是用 {}
包含,而不是一些语言中使用的 []
:
func main() {
var arr1 [3]int
arr1 = [3]int{1, 2, 3}
var arr2 [3]string
arr2 = [3]string{"go", "java", "javascript"}
fmt.Println(arr1) // [1 2 3]
fmt.Println(arr2) // [go java javascript]
}
我们注意到,打印出来的数组值还是使用 []
包含的,但是没有使用 ,
隔开。如果是写 JavaScript 的前端,可能会不习惯 Go 语言中这种定义数组的方式,熟悉就好了。
数组可以定义和赋值一起写,即:
func main() {
arr1 := [3]int{1, 2, 3}
arr2 := [3]string{"go", "java", "javascript"}
fmt.Println(arr1) // [1,2,3]
fmt.Println(arr2) // [go java javascript]
}
这样代码更简洁。
长度未知的数组的定义
有时候我们要定义一个数组时,并不能预测它需要多大的长度,而且 Go 语言数组不可以修改长度,所以此时就需要一种方式能让我们定义可变长度的数组。Go 语言中提供了 ...
操作符来实现这个功能,使用如下:
func main() {
arr1 := [...]int{1, 2, 3}
fmt.Println(arr1) // [1 2 3]
fmt.Printf("%T", arr1) // %T 表示打印值类型,数组 arr1 的类型是 [3]int
}
使用 ...
来替代具体的长度数值,就可以在赋值时自动推断出数组长度,需要注意此时数组的类型中的长度,是根据具体数组值来推断的。
指定数组索引值初始化数组
数组的每一项值,可以使用索引获取,索引值从 0 开始,最大索引是 len-1
func main() {
arr := [3]int{3, 6, 9}
fmt.Print(arr[1]) // 6
}
而在数组初始化时,也可以使用索引来指定值,比如:
func main() {
arr := [...]int{2, 3: 1}
fmt.Print(arr) // [2 0 0 1]
}
代码中数组第一项值是 2
,然后指定索引为 3 的值是 1
,此时会自动补全中间两位的值为 0
。注意这时候的数组长度不能小于索引,如这样就是错的:
arr := [3]int{2, 3: 1} // error: array index 3 out of bounds
指定数组的长度是 3,但是索引最大也是 3,此时数组应该长度应该是 4,所以报错了。
多维数组
Go 语言支持多维数组,这里以二维数组为例。
定义二维数组例子:
func main() {
arr := [3][2]string{
{"北京", "上海"},
{"杭州", "南京"},
{"广州", "深圳"},
}
fmt.Println(arr) // [[北京 上海] [杭州 南京] [广州 深圳]]
fmt.Printf("%T", arr) // [3][2]string
fmt.Println(arr[1][1]) // 南京
}
其实也很好理解,[3][2]string
表示二维数组的长度是 3,数组每一项是类型为 [2]string
的一维数组。注意二维数组赋值时使用的始终是 {}
,我差点在里面写成 []
,这是 js 写多的后果~
有一个注意的地方就是在多维数组中,...
只能用在第一层,拿上面例子来说明:
// ... 使用在外层可以自动推断二维数组的长度
arr := [...][2]string{
{"北京", "上海"},
{"杭州", "南京"},
{"广州", "深圳"},
}
// 下面这样 ... 使用在内层是错误的
arr := [3][...]string{
{"北京", "上海"},
{"杭州", "南京"},
{"广州", "深圳"},
}
遍历数组
Go 语言遍历数组,主要有两种方法,一个是用 for
循环遍历,另一个是用 range
遍历,这里简单写几个例子。
使用 for
循环遍历:
// 遍历一维数组
func main() {
arr := [3]string{"Golang", "Java", "JavaScript"}
for i := 0; i < len(arr); i++ {
fmt.Println(arr[i])
}
}
// 输出
Golang
Java
JavaScript
// 遍历二维数组
func main() {
arr := [2][3]string{
{"Golang", "Java", "JavaScript"},
{"Python", "PHP", "C"},
}
for i := 0; i < len(arr); i++ {
fmt.Println(arr[i])
}
}
// 输出
[Golang Java JavaScript]
[Python PHP C]
使用 range
遍历:
// 遍历一维数组
func main() {
arr := [3]string{"Golang", "Java", "JavaScript"}
for idx, val := range arr {
fmt.Println(idx, val)
}
}
// 输出索引和值
0 Golang
1 Java
2 JavaScript
// 遍历二维数组
func main() {
arr := [2][3]string{
{"Golang", "Java", "JavaScript"},
{"Python", "PHP", "C"},
}
for _, val := range arr { // 当我们要忽略索引值时,可以使用 _
fmt.Println(val)
}
}
// 输出
[Golang Java JavaScript]
[Python PHP C]
数组是值类型
不得不说一嘴,Go 语言中的数组是值类型,这跟 js 这种动态语言中的数组很不一样,在接触 Go 语言之前,我一直坚信数组就是引用类型,但现在要习惯不同编程语言的特性。
值类型和引用类型的代码区别就是,当修改复制出来的数据时,会不会改变原数据,如下代码证明了 Go 中的数组是值类型:
func main() {
nums := [3]int{3, 5, 7}
copy_nums := nums // 复制数组
copy_nums[0] = 4 // 修改复制数组的值
fmt.Println(nums) // [3 5 7]
fmt.Println(copy_nums) // [4 5 7]
}
如果数组是引用类型,那么原数组 nums
的值也应该是 [4 5 7]
,但是它还保持原值,所以它是值类型。