如何在Golang中掌握指针赋值与拷贝_Golang地址传递与值传递区别

17次阅读

go中只有值传递,&x取地址得T类型值,p解引用读取指向的值;传指针本质是传地址值副本,修改指针本身不影响原变量。

如何在Golang中掌握指针赋值与拷贝_Golang地址传递与值传递区别

Go 里 &* 到底在干啥

Go 中没有“引用传递”,只有值传递;但你可以传一个指针类型的值,它本身存的是地址。所以关键不是“传什么”,而是“传进去的东西是什么类型”。&x 取出变量 x 的内存地址,得到一个 *T 类型的值;*p 是解引用,从地址 p 读出它指向的 T 类型的值。

常见错误是以为写了 func f(p *int) { p = &y } 就能改外面的指针变量本身——其实不能,因为 p*int 的副本,你只是把它内部存的地址换掉了,原变量没变。

  • &x 的结果是一个新生成的指针值(地址),类型为 *T
  • *p 操作需要 p != nil,否则 panic: invalid memory address or nil pointer dereference
  • 结构体字面量里用 &S{...} 得到的是指向新分配结构体的指针,不是对已有变量取地址

函数参数传 *T 还是 T?看这三点

决定是否用指针传参,不看“要不要修改”,而看三件事:数据大小、是否真要修改原值、API 一致性。

  • 小类型(如 intbool[3]int)传值开销小,优先传值;大结构体(比如含 []byte 或几十字段)传指针避免拷贝
  • 如果函数逻辑上“必须修改调用方状态”,比如 json.Unmarshal(&v),那就得传 *T;否则传值更安全、更易测试
  • 同个类型的方法集最好统一:如果已经有 (*T).Method(),那其他函数也建议接收 *T,避免混用造成理解成本
type User Struct { 	Name string 	Age  int }  func updateUser(u *User) { // 明确表示会改 u 指向的值 	u.Name = "Alice" } func copyUser(u User) User { // 不动原值,返回新副本 	u.Name = "Bob" 	return u }

切片mapchannel 为什么“像引用”但仍是值传递

它们底层都是结构体(header),包含指针字段。例如 slice 实际是 struct{ ptr *elem, len, cap }。传 slice 时,这个 header 被完整拷贝,但其中的 ptr 字段仍指向同一块底层数组——所以改元素会反映到原 slice,但做 s = append(s, x) 可能导致扩容,新 header 的 ptr 就指向别处了,原 slice 不受影响。

立即学习go语言免费学习笔记(深入)”;

  • mapchannel 同理:header 拷贝,内部指针共享;但 make(map[int]int) 返回的是 header 值,不是指针
  • 想让函数彻底控制底层数组(比如强制扩容并让调用方看到),必须传 *[]T,即指向切片 header 的指针
  • 常见坑:func badappend(s []int) { s = append(s, 99) } —— 外面的 slice 完全不受影响
func goodAppend(s *[]int) { 	*s = append(*s, 99) } nums := []int{1, 2} goodAppend(&nums) // nums 现在是 [1 2 99]

什么时候必须用 new(T)&T{}

new(T) 返回 *T,且把内存清零;&T{} 也返回 *T,但按字段顺序初始化(未写的字段仍为零值)。二者都不常用,多数时候直接写 &User{Name: "X"} 更清晰。

  • new(T) 唯一不可替代场景:你需要一个零值指针,但 T 没有字面量语法(比如接口、函数类型)——但这种情况极少
  • &T{} 常用于初始化结构体,尤其字段多或含嵌套时;注意 &struct{X int}{1} 合法,但 struct{X int}{1} 是值,不是地址
  • 不要为了“统一风格”而滥用:var x *int; x = new(int) 不如 x := new(int) 直观,更不如 var x int; px := &x 明确

真正容易被忽略的是:Go 的“值传递”规则贯穿一切,包括 Interface{}。当你把 *T 赋给 interface{},传进去的仍是那个指针值的副本——但它所指的地址没变,所以通过 interface{} 调用方法仍能修改原值。这点让很多人误以为 interface{} 是引用传递。

text=ZqhQzanResources