一聚教程网:一个值得你收藏的教程网站

最新下载

热门教程

Go 中函数参数传递方式:值传递本质与指针传递的适用场景

时间:2026-07-13 09:08:52 编辑:袖梨 来源:一聚教程网

<p>Go函数参数永远是值传递,传指针实为传地址值,修改解引用后内存才影响原变量;大结构体、需修改原值或方法写字段时才必须用* T;slice/map/channel的可变性源于内部指针,非引用传递。</p>

Go 函数参数永远是值传递,不存在引用传递;所谓“指针能改原值”,是因为你传的是地址这个值,解引用后操作的是同一块内存。

func f(x T) 的 x 永远是副本

不管 Tintstring 还是 struct{}x 都是调用时传入值的一份拷贝。修改 x 不会影响调用方的原始变量。

  • int:副本里存的是数字(比如 42),改它只是改副本
  • *int:副本里存的是地址(比如 0xc00001a080),*x = 100 写的是该地址指向的内存
  • []bytemap[string]int:它们底层是含指针的结构体,所以副本仍指向同一底层数组或哈希表——但这仍是值传递,只是“值”里带指针

什么时候必须用 *T 而不是 T

不是“想改就用指针”,而是不传指针就完不成目标时才必须用。

  • 需要修改调用方的原始变量:比如 swap(a, b *int)json.Unmarshal(data []byte, v interface{}) 要求 v 是指针
  • 结构体很大(字段多、含大 slice/map、或数组长度大):避免复制开销,例如 type Config struct { Data [1e6]byte },传 Config 会拷贝 1MB
  • 方法接收者需写字段:如 func (u *User) SetName(n string) { u.Name = n },值接收者 (u User) 改了也白改

常见 panic 和误判点

nil 指针进函数再解引用,会直接 panic: runtime error: invalid memory address or nil pointer dereference

  • nil *User 然后执行 u.Name = "x" → panic
  • 但传 User{}(零值)是安全的,哪怕字段是空 slice 或 map
  • 别以为 “slice 是引用类型就能改原 slice”:对 ss = append(s, x) 不会影响调用方,因为 append 可能分配新底层数组,只改了副本里的 ptr

真正容易被忽略的是:切片、map、channel 的“可变性”来自其内部指针字段,不是语言层面的引用传递;而 *[]T*map[K]V 这类指针类型本身可比较,但 []Tmap[K]V 不可比较——这点在做 map key 或单元测试断言时经常踩坑。

热门栏目