Golang使用指针修改结构体字段的示例解析

传结构体指针才能修改原字段,因为Go函数参数是值传递,传结构体副本无法影响原变量,只有传*Struct并通过解引用才能写回原始内存。

为什么传结构体指针才能修改原字段

Go 函数参数是值传递,传 struct 本身会复制整个结构体。哪怕只改一个 int 字段,函数内操作的也是副本,原变量不受影响。只有传 *MyStruct,函数拿到的是内存地址,才能通过解引用(*)写回原始内存位置。

修改结构体字段的两种常见写法对比

假设结构体定义为:

type User struct {
    Name string
    Age  int
}
下面两种方式都能改字段,但适用场景不同:

  • 直接在函数内解引用赋值:适合单次、明确字段名的操作
  • 用方法接收者声明为指针:适合复用逻辑、链式调用或需要同时读写多个字段

错误示范(传值无法修改):

func updateUser(u User) {
    u.Name = "Alice" // 只改了副本
}
u := User{Name: "Bob"}
updateUser(u)
fmt.Println(u.Name) // 输出 Bob,没变

正确写法(传指针):

func updateUser(u *User) {
    u.Name = "Alice" // u 是指针,u.Name 等价于 (*u).Name
}
u := User{Name: "Bob"}
updateUser(&u)
fmt.Println(u.Name) // 输出 Alice

方法接收者用 *T 还是 T?看是否要改字段

如果方法里要修改接收者的字段,接收者必须是 *T。否则编译报错:cannot assign to u.Name in method expression

  • func (u User) setName(n string)u 是副本,u.Name = n 不影响调用方
  • func (u *User) setName(n string):可安全修改原结构体的 Name 字段
  • 即使结构体很大,用 *T 接收者也更高效——只传 8 字节地址,而非整个结构体拷贝

容易忽略的 nil 指针解引用 panic

传入 nil 指针后直接访问字段,运行时 panic:panic: runtime error: invalid memory address or nil pointer dereference

  • 调用前检查是否为 nil
    func (u *User) setName(n string) {
        if u == nil {
            return // 或 panic("User is nil")
        }
        u.Name = n
    }
  • 构造函数返回 *User 时,也要避免返回未初始化的指针(如 var u *User),应显式 &User{...} 或用 new(User)
  • JSON 解析到结构体指针字段时,若源数据缺失该字段,对应指针字段为 nil,访问前务必判空

字段级指针(比如 Age *int)和结构体指针是两回事,别混淆。这里讨论的是“把结构体地址传进去改它自己”,不是“结构体里存了个指针字段”。