对比 Go 中传址传参和传值传参

Go 参数可以传指针(引用)和传值。本文将比较这两种方式,着重对比二者的不同点。

传指针 vs 传值

严格来说,Go 中传参数只有一种形式 - 传值。变量当作参数传递时,变量会被复制,这个复制值再传递到函数或者方法中。这个复制值存放在不同的内存地址中。

当一个变量当作指针传递时,指向相同内存地址的指针得到复制。通过例子来看看其中的不同。

传值
package main

import "fmt"

type Person struct {
    firstName string
    lastName  string
}

func changeName(p Person) {
    p.firstName = "Bob"
}

func main() {
    person := Person {
        firstName: "Alice",
        lastName: "Dow",
    }

    changeName(person)

    fmt.Println(person)
}

运行得到:

{Alice Dow}

注意到虽然 changeName 函数改变 firstName 为 “Bob” ,但是这并没有改变 main 函数中 person 变量。这是因为 changeName 函数改变的是 person 变量的拷贝值,而不是它自身。

传指针
package main

import "fmt"

type Person struct {
    firstName string
    lastName  string
}

func changeName(p *Person) {
    p.firstName = "Bob"
}

func main() {
    person := Person {
        firstName: "Alice",
        lastName: "Dow",
    }

    changeName(&person)

    fmt.Println(person)
}

运行得到:

{Bob Dow}

示例中,main 函数中的 person 变量被 changeName 函数修改了。这是因为 &personp  是两个结构相同并且存储的内存地址也相同的指针。

如何选择

通常根据应用场景来选择。下来来看看常见的使用案例。

变量不变

保持变量不变,只能传值。这样变量不会被下游的程序修改。反之,如果希望改变变量的值,那就传指针。

变量拥有大的数据结构

如果变量拥有大的数据结构,同时对性能有要求。那么优先选择传指针。这样可以避免在内存中复制整个数据结构。

变量是 map 或 slice

Maps 和 slices 在 Go 里面是引用类型,应该传值。

传值通常代价更小

尽管 Go 有点像 C,但是它的编译过程不同。C 特征不都能应用到 Go 上。Go 中传值可能比传指针代价更小。因为 Go 使用逃逸分析了来确定变量能否被安全存储在函数的栈中,这比存储在堆中代价更小。传值简化了逃逸分析,让其更容易存储在栈中。

结论

如何传递变量通常由变量类型和使用场景决定的。否则,建议传值。同时维持团队内选择的一致性也很重要,避免造成混乱。

本文中的所有译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。

原文地址:https://goinbigdata.com/golang-pass-by-p...

译文地址:https://learnku.com/go/t/61018

本文为协同翻译文章,如您发现瑕疵请点击「改进」按钮提交优化建议
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!