Go默认值传递,修改参数副本不影响原变量;需传指针才能写回原值;大struct、需修改或避免拷贝时用指针;slice/map/chan本身是引用类型,传值即可修改底层数组,除非要改其header才需指针。

为什么修改函数参数时,有些改动不生效?
因为 Go 默认是值传递:传入函数的是变量的副本,对副本的修改不会影响原始变量。只有传指针(&v)才能让函数内操作反映到原变量上。
常见错误现象:func modify(s string) { s = "new" } 调用后原字符串不变;而 func modify(s *string) { *s = "new" } 才能改成功。
- 值类型(
int、string、struct等)小对象传值开销小,且天然线程安全 - 大 struct(比如含多个 slice 或大数组)传值会拷贝大量内存,此时应传
*T - 需要函数“写回”数据时,必须用指针——比如
json.Unmarshal第二个参数强制要求*T
接收者用值还是指针?看是否要修改或避免拷贝
方法接收者类型直接影响能否修改原值,也影响调用时的性能和接口实现行为。
- 如果方法要修改接收者字段,必须用指针接收者(
func (p *Person) SetName(n string)) - 如果类型是大 struct,即使只读方法也建议用指针接收者,避免每次调用都拷贝
- 同一类型混用值/指针接收者会导致接口实现不一致:比如
Stringer接口被值接收者实现,则*T类型不自动满足该接口 -
标准库惯例:所有可变方法(如
bytes.Buffer.Write)都用指针接收者
什么时候不该用指针?小心逃逸和 GC 压力
不是所有地方都适合加 *。过度使用指针可能把本该在栈上分配的小变量推到堆上,触发额外 GC。
立即学习“go语言免费学习笔记(深入)”;
- 小基础类型(
int、bool、小 struct)传值比传指针更快,CPU 缓存更友好 -
go tool compile -gcflags "-m" main.go可查看变量是否逃逸;若提示... moved to heap,就要评估是否真需指针 - 闭包中捕获局部变量时,若用指针引用它,该变量必然逃逸——哪怕它原本很小
- map 的 value 是指针类型(如
map[string]*User)时,注意 key 不存在时取值为nil,解引用前必须判空
切片、map、channel 本身已是引用类型,别画蛇添足传指针
它们底层结构包含指针字段(如 slice 有 data 指针),所以传值即可修改底层数组内容,无需再套一层 *[]T。
-
func appendItem(s []int, x int) []int正确;func appendItem(s *[]int, x int)多余且易错 - 但若想修改 slice header 本身(比如扩容后让调用方看到新 header),才需要
*[]T - 同理,
map和chan作为参数传值即可,除非你要替换整个 map 变量(如m = make(map[int]string)),那才需*map[K]V - 误传
*map还可能导致 panic:对nil *map解引用后赋值,会 panic,而直接传map不会
指针不是优化银弹。关键在分清“要不要改原值”和“值本身有多大”。小值传值,大值或需修改时传指针,引用类型(slice/map/chan)按需决定是否要改 header。逃逸分析和实际 profile 比直觉更可靠。










