引入

Go 里要按顺序保存多个相同类型的数据,最基础的方式就是数组。数组长度在声明时就固定了,不能增删,适合数据量确定的场景。虽然实际开发中 Go 切片 用得更多,但数组是理解切片的基础。

正文

定义

定义

数组是用来按顺序保存多个相同类型的数据,长度固定。声明时必须指定长度和元素类型,长度是数组类型的一部分,[3]int[5]int不同类型

语法

// 声明(零值初始化)
var arr [5]int
 
// 声明并初始化
arr := [3]int{1, 2, 3}
 
// 编译器推断长度
arr := [...]int{10, 20, 30}

例子

声明和初始化

var a [3]int
fmt.Println(a) // [0 0 0]
 
b := [3]int{1, 2, 3}
fmt.Println(b) // [1 2 3]
 
c := [...]int{10, 20, 30, 40}
fmt.Println(len(c)) // 4

[…] 让编译器自动算长度,写起来更方便。

通过索引访问和修改

arr := [3]string{"Go", "Rust", "Python"}
 
fmt.Println(arr[0])  // Go
fmt.Println(arr[2])  // Python
 
arr[1] = "Java"
fmt.Println(arr)     // [Go Java Python]

索引从 0 开始,超出范围会编译报错或运行时 panic。

部分初始化

arr := [5]int{0: 10, 3: 40}
fmt.Println(arr) // [10 0 0 40 0]

指定索引赋值,其余元素为零值

遍历数组

arr := [3]int{10, 20, 30}
 
// for 循环
for i := 0; i < len(arr); i++ {
    fmt.Println(i, arr[i])
}
 
// for range
for i, v := range arr {
    fmt.Println(i, v)
}

for range 更简洁,i 是索引,v值的副本

数组是值类型

a := [3]int{1, 2, 3}
b := a
b[0] = 100
 
fmt.Println(a) // [1 2 3](没变)
fmt.Println(b) // [100 2 3]

数组赋值或传参都会复制整个数组,修改副本不影响原始值。

数组比较

a := [3]int{1, 2, 3}
b := [3]int{1, 2, 3}
c := [3]int{1, 2, 4}
 
fmt.Println(a == b) // true
fmt.Println(a == c) // false

同类型数组可以用 == 比较,逐元素对比

多维数组

matrix := [2][3]int{
    {1, 2, 3},
    {4, 5, 6},
}
 
fmt.Println(matrix[0][1]) // 2

多维数组就是数组的元素也是数组。

常见写法

写法说明
var arr [5]int声明,元素为零值
arr := [3]int{1, 2, 3}声明并初始化
arr := […]int{1, 2, 3}编译器推断长度
arr[i]通过索引访问
arr[i] = v通过索引修改
len(arr)获取数组长度
for i, v := range arr遍历数组

特点

  • 数组长度固定,声明后不能改变
  • 长度是类型的一部分,[3]int[5]int不同类型
  • 数组是值类型,赋值和传参会复制整个数组
  • 同类型数组可以用 == 比较
  • 索引越界会编译报错(常量索引)或 panic(变量索引)
  • 实际开发中 Go 切片 用得更多,数组主要用于底层实现

理解

数组就是一个固定大小的盒子,里面按顺序放同一类型的数据。通过索引能快速找到每个元素,但长度不能变,传参还会整个复制,用起来不太灵活。所以在 Go 里,数组更多是切片的基础,日常写代码几乎都用切片代替。

引出

数组长度固定不够灵活,接下来看 Go 切片,学习动态长度的序列,也是 Go 里最常用的集合类型。