MST

星途 面试题库

面试题:Go中实参传递性能优化之值传递与指针传递

在Go语言中,当我们传递一个较大的结构体作为函数实参时,值传递和指针传递在性能上有什么区别?请举例说明何时应该选择值传递,何时应该选择指针传递以优化性能。
29.4万 热度难度
编程语言Go

知识考点

AI 面试

面试题答案

一键面试
  1. 性能区别
    • 值传递:在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])
}
  1. 选择建议
    • 值传递
      • 当结构体较小时,值传递的性能开销可以忽略不计,且值传递代码更清晰,因为函数内部对参数的修改不会影响外部变量。例如:
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
}