文章目录
- 零、概述
- 一、数组基础
- 二、数组拷贝与传参
-
- [1、 值拷贝特性](#1、 值拷贝特性)
- 2、指针数组的拷贝
- 3、函数传参(值传递)
- 三、数组遍历
- 四、多维数组
- 五、数组与切片的区别
零、概述
数组核心语法速查表
操作 | 语法示例 | 说明 |
---|---|---|
声明数组 | var arr [5]int |
长度5,元素默认0 |
初始化数组 | arr := [3]string{"a", "b", "c"} |
完整初始化 |
自动推断长度 | arr := [...]int{1, 2, 3} |
长度为3 |
指定索引初始化 | arr := [4]int{0: 1, 2: 3} |
索引0→1,索引2→3,其余为0 |
访问元素 | value := arr[2] |
索引从0开始 |
遍历数组 | for i, v := range arr { ... } |
使用for range |
多维数组 | var matrix [2][3]float64 |
二维数组,2行3列 |
适用场景
- 需要固定长度的数据集合:如存储月份天数、矩阵数据。
- 性能敏感场景:连续内存结构适合缓存优化,访问速度快于切片。
- 值语义需求:需要确保数据拷贝时的独立性(如游戏棋盘状态)。
注意事项
- 越界检查 :访问超出索引范围的元素会触发
panic
,需通过len(arr)
判断边界。- 大数组性能:拷贝大数组时性能较低,建议使用切片或指针传递。
- 类型一致性:数组长度和元素类型必须完全匹配才能赋值或比较。
一、数组基础
1、数组的本质:固定长度的连续存储结构
Go语言中的数组是值类型,具有以下核心特性:
- 固定长度 :声明时必须指定长度,运行时不可增减(长度是类型的一部分,如
[5]int
和[6]int
是不同类型)。 - 连续内存:元素在内存中连续存放,支持高效的索引访问(时间复杂度O(1))。
- 类型统一 :所有元素类型相同,可存储内置类型(如
int
、string
)或自定义类型(如结构体)。
内存结构示例
go
arr := [4]int{3, 1, 4, 1} // 长度为4的int数组
- 索引从0开始,每个元素占4字节(
int
在32位系统占4字节)。 - 内存地址连续,可通过
arr[i]
直接访问第i
个元素。
2、声明与初始化
** 基本声明语法**
go
var 数组名 [长度]类型 // 未初始化,元素为类型零值
go
var scores [5]float64 // 长度5的float64数组,默认值全为0
var names [3]string // 默认值全为空字符串""
初始化方式
(1)完整初始化
go
arr := [长度]类型{值1, 值2, ...} // 显式指定所有元素
go
primes := [3]int{2, 3, 5} // 长度3,元素为2、3、5
(2)自动推断长度(...
)
go
arr := [...]类型{值1, 值2, ...} // 长度由初始化值个数决定
go
fruits := [...]string{"apple", "banana", "orange"} // 长度3
(3)指定索引初始化
go
arr := [长度]类型{索引: 值, 索引: 值, ...} // 仅初始化指定索引的元素
go
points := [4]int{0: 10, 3: 20} // 索引0→10,索引3→20,其余为0
// 数组为:[10, 0, 0, 20]
3、访问与修改元素
索引访问
语法 :数组名[索引]
,索引范围[0, 长度-1]
,越界会触发运行时panic
。
go
arr := [3]int{1, 2, 3}
fmt.Println(arr[0]) // 输出:1
arr[1] = 4 // 修改索引1的元素为4
指针数组
定义:元素为指针的数组,用于存储多个地址。
go
var ptrs [2]*int // 长度2的int指针数组
a, b := 10, 20
ptrs[0], ptrs[1] = &a, &b // 存储变量地址
fmt.Println(*ptrs[0]) // 输出:10
二、数组拷贝与传参
1、 值拷贝特性
数组是值类型,赋值或传参时会完整拷贝所有元素(包括指针数组中的指针值,但不拷贝指针指向的数据)。
go
arr1 := [2]int{1, 2}
arr2 := arr1 // 拷贝arr1的元素到arr2
arr1[0] = 100 // 修改arr1不影响arr2
fmt.Println(arr2[0]) // 输出:1(原拷贝值)
2、指针数组的拷贝
拷贝的是指针值(地址),若多个指针指向同一数据,修改会同步。
示例:
go
str := "hello"
ptrArr1 := [1]*string{&str}
ptrArr2 := ptrArr1 // 拷贝指针值(均指向str)
*ptrArr1[0] = "world" // 修改str,ptrArr2同步变化
fmt.Println(*ptrArr2[0]) // 输出:world
3、函数传参(值传递)
传递数组时,函数接收的是原数组的副本,修改副本不影响原始数组。
示例:
go
func modify(arr [3]int) {
arr[0] = 100 // 修改副本
}
func main() {
arr := [3]int{1, 2, 3}
modify(arr) // 传递副本
fmt.Println(arr[0]) // 输出:1(原始数组未改变)
}
三、数组遍历
for
循环遍历
go
arr := [3]string{"a", "b", "c"}
for i := 0; i < len(arr); i++ {
fmt.Printf("索引%d: %s\n", i, arr[i])
}
for range
遍历
go
arr := [3]int{10, 20, 30}
for index, value := range arr {
fmt.Printf("索引%d: 值%d\n", index, value)
}
// 输出:
// 索引0: 值10
// 索引1: 值20
// 索引2: 值30
四、多维数组
- 二维数组
go
// 声明:[外层长度][内层长度]类型
matrix := [2][3]int{{1, 2, 3}, {4, 5, 6}} // 2行3列
访问元素 :matrix[行索引][列索引]
go
fmt.Println(matrix[0][2]) // 输出:3(第1行第3列)
- 三维数组
go
cube := [2][2][2]int{
{{1, 2}, {3, 4}},
{{5, 6}, {7, 8}},
}
五、数组与切片的区别
特性 | 数组(Array) | 切片(Slice) |
---|---|---|
长度 | 固定(声明时确定) | 动态(可扩容) |
类型 | 包含长度(如[5]int ) |
不包含长度(如[]int ) |
内存分配 | 连续内存,固定大小 | 底层依赖数组,可动态扩展 |
传参 | 值传递(拷贝所有元素) | 引用传递(仅拷贝切片头信息) |
注意 :切片是数组的"视图",通过arr[:]
可将数组转换为切片。