- 性能区别:
- 值传递:在Go语言中,值传递会复制整个结构体。如果结构体较大,这将消耗较多的内存和时间,因为要在栈上分配空间并复制数据。例如,有一个包含大量字段的结构体
BigStruct
:
package main
import "fmt"
type BigStruct struct {
data [10000]int
}
func passByValue(s BigStruct) {
// 这里对s的操作不会影响原结构体
fmt.Println(s.data[0])
}
- 指针传递:指针传递只传递结构体的内存地址,无论结构体多大,传递的只是一个指针大小(在64位系统上通常是8字节),开销较小。例如:
package main
import "fmt"
type BigStruct struct {
data [10000]int
}
func passByPointer(s *BigStruct) {
// 这里对s指向的结构体的操作会影响原结构体
fmt.Println(s.data[0])
}
- 选择建议:
- 值传递:
- 当结构体较小时,值传递的性能开销可以忽略不计,且值传递代码更清晰,因为函数内部对参数的修改不会影响外部变量。例如:
package main
import "fmt"
type SmallStruct struct {
a int
b int
}
func passSmallByValue(s SmallStruct) {
s.a = 10
fmt.Println(s.a)
}
func main() {
small := SmallStruct{a: 1, b: 2}
passSmallByValue(small)
fmt.Println(small.a) // 这里输出1,原结构体未改变
}
- 指针传递:
- 当结构体较大时,为了避免大量的数据复制带来的性能开销,应选择指针传递。比如前面提到的
BigStruct
结构体,如果使用值传递,每次函数调用都要复制整个10000个元素的数组,开销巨大,而使用指针传递仅传递8字节的指针,性能更优。
- 当函数需要修改结构体内容并希望影响外部变量时,也应使用指针传递。例如:
package main
import "fmt"
type BigStruct struct {
data [10000]int
}
func modifyByPointer(s *BigStruct) {
s.data[0] = 100
}
func main() {
big := BigStruct{}
modifyByPointer(&big)
fmt.Println(big.data[0]) // 输出100
}