Go函数传参均为值传递:传数据则无法修改原变量,传地址(如*int)可修改原值;string是不可变值类型,结构体按需选传值或指针;nil指针解引用必panic;方法接收者建议统一用指针。

函数传参时改不改得到原变量?看传的是数据还是地址
Go 语言没有引用传递,只有值传递——但“值”可以是数据本身(如 int),也可以是内存地址(如 *int)。这是所有困惑的起点。
- 传
func f(x int):x是调用方变量的完整副本,函数里x = 100不会影响外面的原始变量 - 传
func f(p *int):p是地址的副本(比如0xc00001a240),但它仍指向同一块内存,*p = 100就真的改了原始值 - 常见错误:以为
func f(s string)能修改原字符串——不能,string是值类型,哪怕底层有指针,语义上仍是不可变副本
结构体该传值还是传指针?别只看大小,先问要不要改
很多人记成“大结构体用指针”,其实更关键的是语义:你是否需要在函数或方法里修改它?
- 只读场景(如计算哈希、日志打印):传值更安全,避免意外副作用;小结构体(
struct{ ID int; Name string })开销几乎可忽略 - 要修改字段(如
user.SetLastLogin()):必须用指针接收者或指针参数,否则改的只是副本 - 性能陷阱:一个含 1MB 字段的结构体,传值会触发一次完整内存拷贝;而指针永远只传 8 字节地址
- 标准库惯例:
time.Time是值类型(不可变语义),http.Client是指针类型(可配置、可复用)
nil 指针解引用 panic 是怎么发生的?哪些操作会触发
nil 指针不是“空值”,而是“没指向任何有效内存”,一旦解引用就崩溃。
- 典型 panic 场景:
var p *string; fmt.Println(*p)→panic: runtime error: invalid memory address or nil pointer dereference - 容易被忽略的隐式解引用:
if p != nil && *p == "hello"中,如果p是nil,*p会在&&短路前执行,照样 panic - 安全写法:总是先判空再解引用,或用指针字段的零值语义(如结构体中
Name *string,nil表示“未设置”) - map/slice/channel 虽然常被叫“引用类型”,但它们本身是值类型;对
nil map做len(m)合法,但m["k"] = v会 panic
方法接收者用值还是指针?统一用指针最省心
混用值接收者和指针接收者会导致接口实现不一致,而且徒增理解成本。
立即学习“go语言免费学习笔记(深入)”;
- 值接收者方法:无法修改字段,且对大结构体每次调用都复制一次——除非你明确需要隔离性(比如加密运算中防止原始数据被污染)
- 指针接收者方法:能修改字段、避免复制、与接口实现兼容性更好;Go 允许你用值变量调用指针方法(自动取地址),但反过来不行
- 真实坑点:
var u User; u.Save()如果Save是指针方法,u必须是可寻址的(不能是字面量或函数返回值直接调用),否则编译报错:cannot call pointer method on u - 建议:只要结构体不是纯只读小对象(比如
type Status uint8),默认全用指针接收者
最常被忽略的一点:指针不是“高级功能”,而是 Go 控制数据所有权和修改意图的显式语法。你写的每个 & 和 *,都在回答一个问题——这个变量,我到底是想用它的影子,还是它的本体?










