传[]T已足够高效,因切片仅24字节视图头;*[]T仅在需替换整个切片变量时使用,误用会导致逃逸和解引用开销,真正性能瓶颈在于分配、共享与容量管理。

不需要——Go 中传递大切片根本不用加 *[]T,加了反而可能更慢、更容易出问题。
为什么传 []T 已经足够高效
切片不是数据容器,它只是个 24 字节的“视图头”:一个指针 + len + cap。无论底层数组是 1KB 还是 100MB,传参时复制的永远只是这 24 字节。
- 传
[]byte和传[]int开销一样小,和底层数组大小无关 - 函数内对元素的修改(如
s[i] = x)会直接影响原数组,因为指针共享 - 扩容(
append)是否影响调用方,取决于是否触发新分配——但这是逻辑行为,不是传参方式决定的
什么时候才真要传 *[]T
仅当函数必须「替换整个切片变量」,且调用方需要立刻看到新指针、新 len、新 cap ——比如实现一个可增长缓冲区管理器。
- 典型场景:
growIfFull(&buf, 4096),函数内部可能执行*ptr = make([]byte, len(old), newCap) - 普通业务逻辑里几乎不会遇到:增删改元素、遍历、序列化、网络发送,全都不需要
- 误用
*[]T会强制逃逸(编译器把切片变量从栈挪到堆),还多一次解引用,纯属负优化
真正该关心的性能点,不是传参方式
拷贝 SliceHeader 从来不是瓶颈;频繁分配、意外共享、未预分配容量,才是吃内存和拖慢 GC 的元凶。
立即学习“go语言免费学习笔记(深入)”;
- 已知长度?用
make([]T, 0, expectedCap)预分配,避免多次append扩容 - 从大数组里只取几个元素?别写
big[100:105],改用append([]T(nil), big[100:105])切断底层数组引用 - 并发读写同一底层数组?要么加锁,要么主动
copy(dst, src)做隔离 - 怀疑有性能问题?跑
go tool pprof -alloc_space看实际分配热点,而不是猜传参方式
很多人卡在“指针 vs 值”的直觉里,但 Go 的切片设计恰恰是为了让你忘记指针——只要理解它是个轻量视图,就很少需要碰 *[]T。真正容易被忽略的,是底层数组生命周期和共享语义,那才是线上事故的常见源头。










