go函数参数均为值传递,包括指针;传指针可修改所指数据但不能改变原指针指向,需解引用赋值或返回新指针;大结构体或需修改原值时传* t,小结构体按值传更高效;nil指针解引用会panic,须主动检查;方法集隐式转换规则易误判,需注意nil接收者调用限制。

Go 里没有引用传递,只有值传递
Go 函数参数永远是值传递——包括指针本身。你传进去的 *int,实际上传的是那个指针变量的副本,但它指向的地址和原指针一样。所以能通过它修改堆/栈上原数据,但改不了原指针变量自己指向哪儿。
常见错误现象:func modifyPtr(p *int) { p = &newVal } 这样写完,调用方的指针变量没变;你以为“传了引用”,结果发现地址没更新。
- 想改原始变量的值?解引用:用
*p = newVal - 想让调用方的指针指向新地址?必须返回新指针,或传入
**int - 结构体大对象别盲目传指针:小结构体(如
struct{a,b int})按值传可能更快,避免间接寻址开销
什么时候该传 *T 而不是 T
核心判断依据就两条:是否需要修改原值,以及类型大小是否值得避免拷贝。
使用场景举例:
立即学习“go语言免费学习笔记(深入)”;
- 要改字段:比如
func (p *Person) setName(n string) { p.name = n }—— 不传指针,setName改的只是副本 - 大结构体(>16 字节常见):如含切片、map、大数组的 struct,传
*T省拷贝 - 接口值本身很小(2 个指针大小),但接口底层数据大时,传
*interface{}很少必要,通常直接传具体类型指针更清晰
nil 指针解引用 panic 的典型路径
不是所有 *T 参数都非空,但一解引用就崩。最常发生在初始化不完整、配置缺失或提前 return 的分支里。
错误现象:panic: runtime error: invalid memory address or nil pointer dereference
- 接收方必须主动检查:
if p == nil { return }或更明确地报错 - 不要依赖调用方“一定传非 nil”——尤其跨包函数,文档再清楚也不如运行时防御
- 初始化结构体时,用
&T{}而非new(T)更直观;但两者都保证非 nil,除非显式赋nil - 切片、map、channel 类型本身不是指针,但底层有指针字段,
nil切片可安全 len/cap,但不能append或下标赋值
方法集与指针接收者的隐式转换
定义了指针接收者的方法,只能被 *T 调用;但 Go 在某些情况下会自动取地址或解引用,容易误判。
关键规则:
- 变量
v是T类型,且有(*T).Method,那么v.Method()合法 —— 编译器自动加&v - 变量
v是T类型,但只有(T).Method,而你写了(&v).Method(),也合法 —— 自动解引用 - 但如果
v是nil,且调用了(*T).Method,只要方法内不碰*v字段,就不会 panic(比如只读nil接口或做类型判断) - 切记:接口变量存储的是动态类型 + 数据,如果接口值是
nil,其底层数据也是nil,此时断言成*T再调用方法,仍会 panic
nil、哪个结构体值得传指针、以及方法集那几条看似宽松实则咬人的隐式规则。










