Go语言所有函数参数都是值传递,包括指针:传的是地址值的副本,而非引用;slice/map/channel是含指针的值类型,故能修改底层数组但扩容不影响原变量。
直接说结论:Go 所有函数参数都是值传递,func f(x *int) 传的不是“引用”,而是“地址的副本”。所谓“引用传递”是 C++/Java 等语言的概念,Go 从语法到运行时都不支持。初学者常把 *T 参数行为误称为“引用传递”

关键区别不在“怎么传”,而在“传的是什么值”:
func modifyValue(x int):传的是 x 的整数值副本,函数内改 x = 100,外部 a 不变func modifyPtr(x *int):传的是 &a 这个地址值的副本,函数内 *x = 100 就是在改 a 本身x = &b(重赋指针)不会影响调用方的指针变量,因为 x 是地址副本,不是别名func reassign(p *int) {
b := 20
p = &b // 只改了副本 p,不影响外面的指针
}
func main() {
a := 10
p := &a
reassign(p)
fmt.Println(*p) // 还是 10,不是 20
}
它们不是引用类型,而是**含指针的值类型**。例如 []int 底层是 struct{ ptr *int, len, cap },传参时复制这个 struct,但 ptr 字段指向同一片底层数组。所以 s[0] = 100 能生效,不是因为“引用”,而是因为复制后的 struct 仍持有原数据地址。
append 导致底层数组更换),新 slice 的 ptr 指向新地址,原 slice 不受影响*[]int
map 和 channel 同理:内部有指针字段,共享底层数据,但变量本身仍是值传递别凭感觉,按这三条来:
*T(比如 func increment(n *int))*Struct 避免拷贝(如含 [1000]int 的 struct)func (s *MyStruct) Do()),其他方法也建议统一用指针,避免意外拷贝导致状态不一致type Point struct{ X, Y int })用值传递更清晰安全,没必要加 *
最易被忽略的一点:nil 指针解引用会 panic,而值类型不会;所以用指针前,要么确保非 nil,要么显式判空——这不是风格问题,是运行时安全边界。