Go函数参数均为值传递,传指针实为传指针副本;可修改所指向的值,但不能改变原指针本身指向;需根据类型大小和是否需副作用决定是否用指针;解引用前必须检查nil以避免panic。

Go 函数参数传指针时,实际上传的是指针的副本
Go 语言中没有“引用传递”,所有参数都是值传递。即使你传 *int,传进去的也是这个指针变量的拷贝——它和原指针指向同一块内存,但两者地址不同。这意味着你可以通过它修改所指向的值,但无法让外部的指针变量本身指向新地址(除非用 **int)。
常见误解是以为传 *T 就能“改变原指针”,其实只能改变它指向的值。
- 想修改结构体字段?传
*Struct即可 - 想让调用方的指针变量指向新分配的对象?必须传
**T - 传
*T比传T更省内存,尤其对大结构体
什么时候该用指针参数:避免拷贝 + 允许修改
是否用指针,核心看两点:类型大小、是否需要副作用。
- 小类型(
int、bool、string)一般不必要——string本身是只读头,传值开销小 - 大结构体(比如含切片、map、大量字段)建议传
*T,避免复制整个对象 - 函数职责明确要修改输入状态(如
json.Unmarshal必须传*interface{}) - 方法接收者用指针(
func (p *Person) SetName(n string))才能改字段
典型错误:nil 指针解引用 panic
传入 nil 的指针却不检查,直接解引用,运行时 panic:
立即学习“go语言免费学习笔记(深入)”;
func doubleValue(v *int) {
*v = *v * 2 // 如果 v == nil,这里 panic: invalid memory address
}正确做法是显式判断:
- 文档或函数签名应说明是否接受
nil - 若逻辑允许,开头加
if v == nil { return } - 若不允许,可 panic 带明确定位信息:
if v == nil { panic("doubleValue: v cannot be nil") }
完整示例:交换两个整数、修改结构体字段
下面是一个同时演示基础类型指针和结构体指针的函数:
type User struct {
Name string
Age int
}
func swap(a, b int) {
a, b = b, *a
}
func updateUser(u *User, newName string, newAge int) {
if u == nil {
return
}
u.Name = newName
u.Age = newAge
}
// 使用:
x, y := 10, 20
swap(&x, &y) // x=20, y=10
u := &User{Name: "Alice", Age: 30}
updateUser(u, "Bob", 35) // u.Name="Bob", u.Age=35
注意:调用时必须用 &x 取地址;如果传 u(已是指针)就不用再取地址;但如果变量是 User 值类型,就得传 &u。
最容易被忽略的是:指针参数不等于“可以安全忽略 nil”——每次解引用前,到底要不要检查,得由函数契约决定,不是语法强制的。










