数组
Golang 当中数组的定义需要明确指出数组的长度,且长度放在方括号内,方括号在类型之前,变量名之后。
可以使用 var 建立一个默认初始化的数组,也可以使用 :=
建立一个数组,后者可以通过值初始化进行数组的长度推断,但此时需要使用[...]
,即在方括号内加上...
。
需要重点关注的部分如下:
- Golang 当中长度(但类型相同)的数组属于不同的类型;
- 当数组作为实参时,仍然进行值拷贝的方式来完成参数传递,这与大多数语言不同;
- 可以使用指针来达到与引用传递类似的结果,并且在使用指针对数组进行修改时,可以直接显式地对指针进行操作而省略解引用符。
常见的用法如下例所示:
package main
import "fmt"
func printArray(arr [5]int) {
// 由于数组是值类型, 因此需要指定数组的长度
// 需要重点强调的是, [5]int 和 []int 在 Golang 中是完全不同的概念
// []int 是切片, 而 [5]int 才是数组
for i, v := range arr {
fmt.Println(i, v)
}
arr[0] = 100 // 数组是值类型, 在函数中的赋值不会改变实参的值
}
func newPrintArray(arr *[5]int) {
for i, v := range arr { // 不需要显式地使用解引用符
fmt.Println(i, v)
}
arr[0] = 100 // 不需要显式地使用解引用符
}
func main() {
var arr1 [5]int
arr2 := [3]int{1, 3, 5} // 使用 := 时需要显式地给定初值
arr3 := [...]int{2, 4, 6, 8, 10} // 使用 [...] 来隐式推断数组容量
var grid [4][5]int // 定义一个四行五列的数组
fmt.Println(arr1, arr2, arr3)
fmt.Println(grid)
// 遍历数组, 普通方法
for i := 0; i < len(arr3); i++ {
fmt.Println(arr3[i])
}
// 使用 range 遍历
for i := range arr3 {
fmt.Println(arr3[i])
}
// 可以直接使用 range 关键字获取数组下标和下标对应的值
// 非常类似于 python 的 enumerate
for i, v := range arr3 {
fmt.Println(i, v)
}
/* 使用 range 的原因:
- 意义明确, 美观;
- C++ 没有类似的能力;
- Java/Python: 只能 for each value, 不能同时获取 i, v */
/* 数组是值类型(拷贝)
- [10]int 和 [20]int 是不同的类型;
- 调用 func f(arr [10]int) 会拷贝数组 */
printArray(arr1)
printArray(arr3)
// printArray(arr2) 会报错, 原因在于 Golang 当中长度为 3 和 长度为 5 的 array 是不同的数据类型
// 可以使用一个指向数组的指针来在函数中对数组的值进行修改
newPrintArray(&arr1)
printArray(arr1) // 此时 arr1[0] 的值被修改为 100
}