Go 语言数组
定长数组、值语义、多维数组,以及为什么日常都用切片。
Key PointsGo 的数组长度是类型的一部分:`[3]int` 和 `[4]int` 是不同类型。
声明与初始化
Go
var a [3]int // [0 0 0]
b := [3]int{1, 2, 3}
c := [...]int{1, 2, 3, 4} // 长度由编译器数
d := [5]int{1: 10, 4: 50} // 按下标初始化
fmt.Println(a)
fmt.Println(b, len(b))
fmt.Println(c, len(c))
fmt.Println(d)Output
[0 0 0]
[1 2 3] 3
[1 2 3 4] 4
[0 10 0 0 50]值语义
Go
func modify(arr [3]int) {
arr[0] = 999 // 改的是副本
}
x := [3]int{1, 2, 3}
modify(x)
fmt.Println(x) // 原数组不变
// 想改原数组必须传指针
func modifyPtr(arr *[3]int) {
arr[0] = 999
}
modifyPtr(&x)
fmt.Println(x)Output
[1 2 3]
[999 2 3]Array assignment and passing copy the whole thing. Copying three ints is free; copying a hundred thousand elements per call is not. That is why Go uses slices day to day.
遍历
Go
arr := [4]string{"a", "b", "c", "d"}
for i := 0; i < len(arr); i++ {
fmt.Print(arr[i], " ")
}
fmt.Println()
for i, v := range arr {
fmt.Print(i, v, " ")
}
fmt.Println()Output
a b c d
0a 1b 2c 3d 多维数组
Go
var grid [2][3]int
for i := 0; i < 2; i++ {
for j := 0; j < 3; j++ {
grid[i][j] = i*3 + j
}
}
fmt.Println(grid)
// 字面量
m := [2][3]int{
{1, 2, 3},
{4, 5, 6},
}
fmt.Println(m[1][2])Output
[[0 1 2] [3 4 5]]
6数组 vs 切片
| Aspect | Array [3]int | Slice []int |
|---|---|---|
| 长度 | 类型的一部分,固定 | 运行时可变 |
| 赋值 | 整体复制 | 共享底层数组 |
| 传参 | 复制 | 复制头部(3 个字段) |
| 能否 append | 不能 | 能 |
| 常用度 | 少 | 绝大多数场景 |
Arrays beat slices in one case: fixed small length, e.g.
sha256.Sum256 returning [32]byte. Arrays can be map keys; slices cannot.声明与初始化
Go
var a [3]int // [0 0 0]
b := [3]int{1, 2, 3}
c := [...]int{1, 2, 3, 4} // 长度由编译器数
d := [5]int{1: 10, 4: 50} // 按下标初始化
fmt.Println(a)
fmt.Println(b, len(b))
fmt.Println(c, len(c))
fmt.Println(d)Output
[0 0 0]
[1 2 3] 3
[1 2 3 4] 4
[0 10 0 0 50]值语义
Go
func modify(arr [3]int) {
arr[0] = 999 // 改的是副本
}
x := [3]int{1, 2, 3}
modify(x)
fmt.Println(x) // 原数组不变
// 想改原数组必须传指针
func modifyPtr(arr *[3]int) {
arr[0] = 999
}
modifyPtr(&x)
fmt.Println(x)Output
[1 2 3]
[999 2 3]数组赋值和传参都是整体复制。三个 int 复制无所谓,十万个元素的数组每次传参都是灾难。这就是 Go 日常用切片而不是数组的原因。
遍历
Go
arr := [4]string{"a", "b", "c", "d"}
for i := 0; i < len(arr); i++ {
fmt.Print(arr[i], " ")
}
fmt.Println()
for i, v := range arr {
fmt.Print(i, v, " ")
}
fmt.Println()Output
a b c d
0a 1b 2c 3d 多维数组
Go
var grid [2][3]int
for i := 0; i < 2; i++ {
for j := 0; j < 3; j++ {
grid[i][j] = i*3 + j
}
}
fmt.Println(grid)
// 字面量
m := [2][3]int{
{1, 2, 3},
{4, 5, 6},
}
fmt.Println(m[1][2])Output
[[0 1 2] [3 4 5]]
6数组 vs 切片
| 对比项 | 数组 [3]int | 切片 []int |
|---|---|---|
| 长度 | 类型的一部分,固定 | 运行时可变 |
| 赋值 | 整体复制 | 共享底层数组 |
| 传参 | 复制 | 复制头部(3 个字段) |
| 能否 append | 不能 | 能 |
| 常用度 | 少 | 绝大多数场景 |
只有一种情况数组比切片好:长度固定且很小,比如
sha256.Sum256 返回 [32]byte。它能作为 map 的 key,切片不能。