Go中值类型函数传参会复制副本,修改不影响原变量;结构体同理;需改用指针传参才能修改原始值,且更高效。

在 Go 语言中,值类型(如 int、float64、bool、struct 等)在函数传参时会进行内存复制。这意味着函数接收到的是原始数据的副本,对参数的修改不会影响原始变量。这种行为源于 Go 的“按值传递”机制。
值类型的传参是复制
当一个值类型变量作为参数传递给函数时,Go 会在栈上创建该变量的一个完整拷贝。函数内部操作的是这个拷贝,原变量不受影响。
示例:
package mainimport "fmt"
立即学习“go语言免费学习笔记(深入)”;
func modifyValue(x int) { x = x * 2 fmt.Println("函数内 x =", x) // 输出:函数内 x = 20 }
func main() { a := 10 modifyValue(a) fmt.Println("main 中 a =", a) // 输出:main 中 a = 10 }
尽管 x 在函数中被修改为 20,但 a 的值仍然是 10,因为传入的是副本。
结构体也是值复制
结构体是典型的值类型。如果将结构体传入函数,整个结构体都会被复制一份。
示例:
package mainimport "fmt"
立即学习“go语言免费学习笔记(深入)”;
type Person struct { Name string Age int }
func updatePerson(p Person) { p.Age += 1 p.Name = "Updated" fmt.Printf("函数内: %+v\n", p) }
func main() { person := Person{Name: "Alice", Age: 30} updatePerson(person) fmt.Printf("main 中: %+v\n", person) // Age 仍为 30, Name 仍为 "Alice" }
即使函数中修改了字段,原始结构体未受影响。每次调用都涉及字段级别的内存复制。
如何避免复制?使用指针
若希望函数能修改原始值,应传递指针。指针本身是值,但指向同一块内存地址。
修改上例使用指针:
func updatePerson(p *Person) {
p.Age += 1
p.Name = "Updated"
}
func main() {
person := Person{Name: "Alice", Age: 30}
updatePerson(&person)
fmt.Printf("main 中: %+v\n", person) // 输出修改后的值
}
此时函数操作的是原始结构体的内存位置,修改生效。指针传递只复制地址(通常是 8 字节),大幅减少开销,尤其对大型结构体。
值复制的性能考虑
小类型(如 int、bool)复制成本低,无需担心。但大结构体频繁复制会影响性能和内存占用。
- 复制行为发生在栈上,速度快但仍有代价
- 深层嵌套结构体也会逐字段复制
- 数组(非 slice)也是值类型,同样被复制
建议:对于大对象,优先使用指针传参以避免不必要的内存开销。
基本上就这些。理解值类型的复制行为,有助于写出更高效、预期一致的 Go 代码。不复杂但容易忽略。










