Go中数组是值类型,传递或遍历会拷贝,影响性能;使用指向数组的指针(*[N]T)可避免复制,实现原地操作,比传值快100+倍,且比切片更安全可控。

在 Go 中,数组是值类型,直接传递或遍历会触发拷贝,影响性能;而使用指针(尤其是指向数组的指针)可避免复制,实现原地遍历与修改,显著提升大数组操作效率。
理解数组指针与切片的区别
Go 中 *[N]T 是指向固定长度数组的指针,它本身很小(仅存地址),解引用后可直接读写原数组;而切片 []T 是三元结构(底层数组指针、长度、容量),虽也高效,但若需严格限定长度、避免意外扩容或确保内存布局连续,数组指针更可控。
- 声明方式:
arr := [3]int{1,2,3}; ptr := &arr→ptr类型为*[3]int - 访问元素:
(*ptr)[i]或简写为ptr[0][i](Go 允许对数组指针直接用下标,等价于先解引用) - 传参时:函数接收
*[1000]int只传 8 字节地址,而非 8000 字节数组副本
用指针遍历并修改大数组的典型写法
以下是一个将百万级整数数组全部加 1 的高效示例:
func incrementAll(ptr *[1e6]int) {
for i := range ptr {
(*ptr)[i]++ // 明确解引用写法,语义清晰
// 或直接写 ptr[0][i]++(效果相同)
}
}
// 调用
bigArr := [1e6]int{}
incrementAll(&bigArr) // 原数组被修改,无拷贝开销
注意:range ptr 在这里合法,因为 Go 规定对数组指针使用 range 时,会自动解引用并遍历其指向的数组。
立即学习“go语言免费学习笔记(深入)”;
避免常见误区
-
别误用切片代替数组指针:若函数签名是
func f(s []int),传入&arr需显式转成切片arr[:],这会丢失长度信息且可能引发越界;而*[N]int保留编译期长度约束 -
不要返回局部数组的指针:如
func bad() *[3]int { a := [3]int{}; return &a }是危险的——a在栈上分配,函数返回后内存可能被复用 -
循环中避免重复解引用:高频场景下,可先赋值
data := *ptr(此时仍是数组值拷贝!),不如直接用ptr[0][i]稳妥;真正零拷贝的操作始终基于*ptr或ptr[0]
性能对比小提示
对 100 万元素的 [1e6]int:
- 传值调用(
func f(arr [1e6]int)):每次调用拷贝 8MB 内存,GC 压力大,实测慢 100+ 倍 - 传切片(
func f(s []int)):传参快,但需额外检查边界、无长度保障 - 传数组指针(
func f(ptr *[1e6]int)):参数轻量、安全、编译器可做更多优化,推荐用于已知尺寸的大数组批量处理











