Go只有传值,指针传的是地址副本;结构体需传指针才能修改原值;切片/map/channel是含指针的值类型;nil指针解引用会panic;关键在所传值是否指向原始数据。

Go 里没有“传引用”,只有“传值”——但指针变量的值是地址
Go 语言中所有参数传递都是值传递,func f(x int) 和 func f(p *int) 的区别不在于“传引用”或“传值”,而在于你传进去的“值”本身是什么:一个是整数副本,一个是内存地址副本。误以为 Go 支持引用传递,是初学者踩坑最频繁的认知偏差。
修改结构体字段时,为什么传指针才生效?
因为结构体默认按值传递,函数内操作的是副本;传 *struct 后,你拿到的是原结构体地址,解引用 (*s).Field 或简写 s.Field 就能改原始内存。
-
func updateName(u User) { u.Name = "Alice" }→ 原User不变 -
func updateName(u *User) { u.Name = "Alice" }→ 原User的Name被修改 - 即使结构体很小(如两个
int),也建议方法接收者用指针——否则调用u.Method()会复制整个结构体
切片、map、channel 是“引用类型”?不,它们是含指针的描述符
[]int、map[string]int、chan int 本身是值类型,但它们底层结构包含指向底层数组/哈希表/队列的指针。所以:
-
func appendInt(s []int, v int) []int { return append(s, v) }→ 必须返回新切片,且调用方要赋值:s = appendInt(s, 5) -
func setMap(m map[string]int, k string, v int) { m[k] = v }→ 不需要返回,因为m值里存着指向同一哈希表的指针 - 但若在函数内做
m = make(map[string]int),外部原map不受影响——你只是把那个指针副本重新指向了新地址
常见误用:对 nil 指针解引用 panic
传 *T 并不保证它非 nil;没初始化的指针变量值是 nil,直接解引用会触发 panic: runtime error: invalid memory address or nil pointer dereference。
立即学习“go语言免费学习笔记(深入)”;
func printName(u *User) {
// ❌ 危险!未检查 u 是否为 nil
fmt.Println(u.Name)
// ✅ 应先判断
if u == nil {
fmt.Println("user is nil")
return
}
fmt.Println(u.Name)
}
接口值(interface{})和指针一样,也可能为 nil;但空接口变量本身非 nil,不代表它装的动态值非 nil —— 这点容易混淆,需格外注意。
真正关键的不是“传值还是传引用”,而是“你传的那个值,是否指向可修改的原始数据”。盯住变量的类型本质(int vs *int vs []int),比记口诀管用得多。










