Go函数参数均为值传递,传入的是变量副本;基础类型拷贝值,struct拷贝字段,slice/map/chan拷贝引用信息,故修改元素可生效但重分配不影响原变量,需传指针才能真正修改外部值。

Go 语言中函数参数是值传递,传进去的是变量的副本,修改副本自然不影响原始变量。
Go 的所有函数参数都是值传递
哪怕你传的是 int、string、struct,甚至是 []int 或 map[string]int,Go 都会把该值“拷贝一份”传给函数。注意:这里的“拷贝”对不同类型语义不同——比如 slice 拷贝的是其头信息(指针、长度、容量),但底层数组不会被复制;而 struct 是整个字段逐个拷贝。
-
int、float64、bool等基础类型:拷贝的是数值本身 -
struct:拷贝全部字段(若字段含指针,则拷贝指针值,而非指向的内容) -
slice:拷贝 header(含指向底层数组的指针),所以函数内能改元素值,但不能通过append影响原 slice 长度或容量 -
map和chan:拷贝的是底层结构的引用(类似指针),因此可修改其中键值或收发数据
常见误解:为什么修改 slice 元素有时“生效”,有时“不生效”
这是因为 slice 是描述性结构,它本身小且可拷贝,但它的指针字段指向共享的底层数组。所以函数内 s[i] = x 会改到原数组,但 s = append(s, x) 会让 s 指向新底层数组(原变量仍指向旧数组)。
func modifySlice(s []int) {
s[0] = 999 // ✅ 影响外部:改的是底层数组
s = append(s, 100) // ❌ 不影响外部:s 现在指向新底层数组
}
func main() {
a := []int{1, 2, 3}
modifySlice(a)
fmt.Println(a) // 输出 [999 2 3],不是 [999 2 3 100]
}
想真正修改外部变量,得传指针
只有显式传入指针(*T),函数内解引用后赋值,才能改变调用方的原始值。这是最直接、最可控的方式。
立即学习“go语言免费学习笔记(深入)”;
- 传
*int才能改那个int的值 - 传
*MyStruct才能改结构体字段(尤其当结构体较大时,也避免拷贝开销) - 传
*[]int才能让函数重分配 slice 并让外部看到新切片(极少需要,通常说明设计可优化)
func increment(p *int) {
*p++
}
func main() {
x := 42
increment(&x)
fmt.Println(x) // 输出 43
}
最容易被忽略的一点:不是“Go 不支持引用传递”,而是“Go 只有值传递,但值可以是指针”。理解这点,就不再纠结“为什么改不了”,而会主动思考“我传进去的这个值,它到底代表什么”。










