Go语言函数参数按值传递,传入的是原始变量副本,修改副本不影响原变量;基本类型、数组、结构体等值类型均遵循此规则,需显式传指针才能修改外部变量。

Go语言中,函数参数是按值传递的,这意味着传入函数的是原始变量的一个副本。对这个副本的任何修改,都不会影响到调用方的原始变量——尤其是对基本类型(如int、string、bool)、数组、结构体等值类型而言,这一点尤为明显。
值类型参数的本质:复制一份独立数据
当你把一个值类型变量作为参数传给函数时,Go会在栈上为该参数分配一块**全新的内存空间**,并把原变量的值完整拷贝过去。函数内部操作的,是这块新内存里的数据,和外部变量毫无关联。
- 整数、浮点数、布尔值、字符串:都是典型的值类型,传参即复制
-
数组:比如
[3]int,整个数组内容被复制,不是指针 - 结构体(不含指针字段):整个结构体字段逐个复制,包括嵌套的值类型
看一个清晰的例子
下面这段代码直观展示了值传递的行为:
func modify(x int) {
x = 100
fmt.Println("函数内 x =", x) // 输出:100
}
func main() {
a := 42
fmt.Println("调用前 a =", a) // 输出:42
modify(a)
fmt.Println("调用后 a =", a) // 仍然是 42,没变!
}
这里a的值被复制给了参数x,x在函数内被改成100,但a本身完全不受影响。
立即学习“go语言免费学习笔记(深入)”;
为什么结构体也遵循这个规则?
很多人误以为“结构体大,应该传引用”,其实不然。只要没显式用*传指针,结构体就是按值传递:
type Person struct {
Name string
Age int
}
func changeName(p Person) {
p.Name = "Alice" // 修改的是副本
}
func main() {
me := Person{Name: "Bob", Age: 30}
changeName(me)
fmt.Println(me.Name) // 输出 "Bob",不是 "Alice"
}
因为p是me的完整拷贝,改p.Name只动了副本的字段。
想让外部变量被修改?得用指针
如果确实需要函数内部修改影响外部,唯一可靠的方式是传指针:
- 把
modify(x int)改成modify(x *int),然后用*x = 100 - 把
changeName(p Person)改成changeName(p *Person),再用p.Name = "Alice" - 调用时写
modify(&a)或changeName(&me)
这时传的是地址,函数操作的是同一块内存,自然能改变原始值。
理解值传递是掌握Go内存模型的基础。它让函数行为更可预测、更安全——没有意外的副作用。只有当你明确需要共享状态时,才引入指针。










