传*t真正减少内存拷贝仅当t为大结构体(如含[]byte或嵌套结构);小结构体传值更优,因缓存友好且避免解引用开销;需结合逃逸分析与接口实现需求综合判断。

直接传指针能避免结构体或大对象的值拷贝,但不是所有场景都该这么干——关键看数据大小、是否需修改原值、以及逃逸分析结果。
什么时候传 *T 真正减少内存拷贝
go 中函数参数是值传递,传 T 会复制整个值;传 *T 只复制一个指针(8 字节)。但只有当 T 是较大结构体(比如字段多、含 slice/map/interface)时,收益才明显。
- 小结构体(如
type Point Struct{ x, y int })传值比传指针更快——CPU 缓存友好,且避免解引用开销 - 大结构体(如含
[]byte或多个嵌套结构)传指针可显著降低栈分配和复制成本 - 注意:哪怕你传
*T,如果函数内对它做了new(T)或赋值给全局变量,仍可能触发堆分配(逃逸)
go tool compile -gcflags="-m" 看清逃逸行为
编译器决定变量分配在栈还是堆,直接影响拷贝和 GC 压力。不看逃逸分析就乱加指针,可能白忙活甚至更慢。
- 运行
go build -gcflags="-m -l" main.go(-l关闭内联,让分析更准) - 关注输出中的
... escapes to heap或... does not escape - 例如:
func f(v MyStruct) { ... }若v被取地址并返回,编译器会强制把它分配到堆——此时传*MyStruct反而让调用方多一次栈上指针复制
接口类型和方法集让指针 vs 值更微妙
方法接收者用值还是指针,不仅影响拷贝,还决定能否满足接口——这是常被忽略的隐性成本。
立即学习“go语言免费学习笔记(深入)”;
- 若某类型
T只有(*T).Method()方法,那T{}值本身不能赋给含Method()的接口变量,必须显式取地址:&t - 反过来,如果只定义了
(T).Method(),那*T也能调用(自动解引用),但每次调用都会拷贝T——对大结构体就是灾难 - 结论:大结构体 + 需实现接口 → 接收者统一用
*T;小结构体 + 无接口要求 → 优先用值接收者
最易被忽视的是:指针带来的副作用(修改原值)和并发风险(多个 goroutine 同时写同一块内存)。性能提升不该以逻辑错误为代价——先确认是否真需要共享可变状态,再决定用不用指针。