不是必须,但不传指针几乎一定吃亏;大定长数组传参会完整复制,开销大且风险高;应使用[N]T类型指针传地址,避免误用[]T或非法类型转换。

Go 里传大数组必须用指针吗?
不是必须,但不传指针几乎一定吃亏。Go 函数参数是值传递,[]int 是切片(含指针、长度、容量三字段),传它本身开销小;但 [1000000]int 这种定长数组,传参时会完整复制 4MB 内存——这会卡顿、拖慢 GC、还可能触发栈溢出。
怎么安全地把大数组地址传进函数?
用指向数组的指针,类型写成 *[N]T,不是 *[]T(后者是“指向切片”的指针,极少用)。关键点:
-
var arr [1e6]int→ 传&arr,函数接收func f(p *[1e6]int) - 不能直接对
[N]T取地址再转成*[]T:Go 不允许这种类型转换 - 如果原数据来自切片(比如
make([]int, 1e6)),先用unsafe.Slice+unsafe.Pointer转成数组指针(需谨慎,见下条)
用 unsafe.Pointer 转切片为数组指针要注意什么?
这是绕过类型系统取巧的做法,常见于高性能场景(如序列化、零拷贝网络),但极易出错:
- 切片底层数组长度必须 ≥ 目标数组长度,否则越界读写
- 必须确保切片在整个函数调用期间不被 GC 回收或重新切片(例如不要传局部
make([]int, N)的结果,而应传入已分配好的长生命周期切片) - 示例:将
data := make([]byte, 1 当作 <code>[1 用:<pre class="brush:php;toolbar:false;">ptr := (*[1 << 20]byte)(unsafe.Pointer(&data[0]))</pre>,之后可传 <code>&ptr或直接解引用
传 *[N]T 比传 []T 真的更快吗?
只在特定条件下成立:当函数内部**只读或只写固定索引范围**,且编译器能做足够优化时。但要注意:
立即学习“go语言免费学习笔记(深入)”;
- 传
[]T更灵活,支持len/cap,编译器对它的边界检查和内联也更成熟 - 传
*[N]T后,每次访问仍要解引用((*p)[i]),现代 CPU 对缓存友好,但代码可读性下降 - 实测中,若函数体简单(如累加求和),两者性能差异常小于 5%;真正瓶颈往往在算法或内存布局,而非这一层传参方式
别为了省一次复制,写出难 debug 的 unsafe 逻辑。先 profile,确认这里真是热点,再动刀。











