在 Go语言结构体 的使用中,值传递和指针传递是两个核心概念。对于初学者来说,理解它们的区别不仅有助于写出正确的代码,还能避免常见的性能陷阱。本文将用通俗易懂的方式,带你彻底搞懂 Go 中结构体的这两种传递方式。
值传递(Pass by Value)是指函数接收的是原始数据的一个副本。在 Go 语言中,当你把一个结构体作为参数直接传入函数时,默认就是值传递。
这意味着:函数内部对结构体字段的修改,不会影响原始结构体。
package mainimport "fmt"// 定义一个简单的结构体type Person struct { Name string Age int}// 值传递:接收结构体副本func updateByValue(p Person) { p.Age = 30 // 修改的是副本 fmt.Println("函数内修改后:", p)}func main() { person := Person{Name: "小明", Age: 25} fmt.Println("调用前:", person) updateByValue(person) // 传入结构体 fmt.Println("调用后:", person) // Age 仍然是 25} 运行结果:
调用前: {小明 25}函数内修改后: {小明 30}调用后: {小明 25} 可以看到,函数内部虽然把 Age 改成了 30,但原始变量 person 并未改变。这就是 值传递 的典型表现。
指针传递(Pass by Pointer)是指函数接收的是结构体的内存地址。在 Go 中,你只需在参数前加 *,并在调用时使用 & 取地址即可。
这种方式下,函数内部对结构体的修改会直接影响原始变量。
// 指针传递:接收结构体指针func updateByPointer(p *Person) { p.Age = 30 // 修改的是原始结构体 fmt.Println("函数内修改后:", *p)}func main() { person := Person{Name: "小明", Age: 25} fmt.Println("调用前:", person) updateByPointer(&person) // 传入结构体地址 fmt.Println("调用后:", person) // Age 变成了 30} 运行结果:
调用前: {小明 25}函数内修改后: {小明 30}调用后: {小明 30} 这次,原始变量 person 的 Age 被成功修改了!这就是 指针传递 的作用。
选择哪种方式,主要看两个因素:
例如,一个包含多个字段的大结构体:
type UserProfile struct { ID int Name string Email string Address string Phone string Avatar []byte // 可能很大 Settings map[string]interface{}} 对这样的结构体使用 值传递 会导致大量内存拷贝,影响程序性能。因此,在实际开发中,尤其是涉及 Go性能优化 时,大结构体通常采用指针传递。
1. 切片、map、channel 是引用类型:即使你用值传递它们,函数内部的修改也会影响原始变量(因为它们底层包含指针)。但这不适用于结构体!
2. 方法接收者也要注意:如果你定义结构体方法,接收者是值还是指针,也会决定能否修改原始数据。
// 值接收者:不能修改原始结构体func (p Person) ChangeName(name string) { p.Name = name // 无效}// 指针接收者:可以修改func (p *Person) ChangeName(name string) { p.Name = name // 有效} - Go语言结构体 默认按值传递,安全但可能低效。
- 使用指针传递可修改原始数据,并提升 Go性能优化 效果。
- 小结构体(如只有几个基本类型字段)可用值传递;大结构体或需要修改时,务必用指针。
- 理解 值传递 和 指针传递 的区别,是写出高效、正确 Go 代码的基础。
掌握这些知识后,你就能更自信地使用 Go 语言结构体,避免踩坑,写出高性能的应用程序!
本文由主机测评网于2025-12-20发表在主机测评网_免费VPS_免费云服务器_免费独立服务器,如有疑问,请联系我们。
本文链接:https://vpshk.cn/20251210475.html