golang 函数参数传递有值传递和引用传递两种方式。值传递创建参数副本,安全但开销大;引用传递传递参数指针,开销小但存在修改原始值和并发问题的风险。
Golang 中函数参数传递的效率分析
函数参数传递在程序性能中扮演着重要角色,特别是对于大型数据结构或复杂对象。Golang 中提供了两种函数参数传递方式:值传递和引用传递。
值传递
值传递会创建参数值的副本,传递给函数。这是一种安全的传递方式,因为在函数内部对参数进行修改不会影响调用者的原始值。但是,如果传递的参数是大型数据结构或复杂对象,则会导致额外的内存开销和复制时间。
func foo(x int) { x++ // 修改 x 的副本,不会影响调用者原始值 }
引用传递
引用传递传递的是参数的指针,而不是值本身。这可以显着减少内存开销和复制时间,尤其是在传递大型数据结构或复杂对象时。然而,引用传递存在以下缺点:
- 修改参数: 在函数内部对参数指针修改将影响调用者原始值。
- 并发问题: 如果参数是一个共享资源,则引用传递可能会导致并发问题。
func foo(x *int) { *x++ // 修改原始值,因为传递的是指针 }
实战案例
下面是一个比较值传递和引用传递性能的实战案例:
package main import ( "fmt" "time" ) type LargeStruct struct { Data []byte } func main() { // 创建一个大型结构 largeStruct := &LargeStruct{Data: make([]byte, 1000000)} // 使用值传递 start := time.Now() for i := 0; i < 100000; i++ { foo(largeStruct) } elapsed1 := time.Since(start) // 使用引用传递 start = time.Now() for i := 0; i < 100000; i++ { fooPtr(largeStruct) } elapsed2 := time.Since(start) fmt.Println("值传递耗时:", elapsed1) fmt.Println("引用传递耗时:", elapsed2) } func foo(largeStruct LargeStruct) {} func fooPtr(largeStruct *LargeStruct) {}
在该案例中,使用值传递比使用引用传递慢很多,因为每次调用 foo 函数都会复制整个大型结构。