【问题标题】:Why do some values get updated in a func and others don't? [duplicate]为什么有些值会在 func 中更新而其他值不会? [复制]
【发布时间】:2023-04-10 10:17:01
【问题描述】:

比较这两个例子

(来自:https://goinbigdata.com/golang-pass-by-pointer-vs-pass-by-value/

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},所以结构没有改变。

现在在这个例子中

package main

import "fmt"

func main() {
    slice := []string{"a", "b", "c"}

    fmt.Println(slice)
    updateSlice(slice)
    fmt.Println(slice)
}

func updateSlice(slice []string) []string {
    slice[0] = "x"
    return slice
}

输出是

[a b c]
[x b c]

所以切片被函数updateSlice改变了。

有人能解释一下区别吗?

【问题讨论】:

标签: go memory slice


【解决方案1】:

切片是对底层数组的引用。因此,当您将切片传递给函数时,实际上是在传递对底层数组的引用。

在第一个代码 sn-p 中,当您调用 changeName(person) 时,Go 将创建 person 结构的副本并将其传递给 changeName 函数。

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

    changeName(person) //Go will pass a copy of the person struct

    fmt.Println(person)
}

Go 中的切片只是对底层数组的引用;切片不是数组。在第二个示例中,updateSlice(slice) 也按值传递。它会创建slice 的副本。但是,在这种情况下,Go 正在创建对数组的引用的副本。这意味着,“切片的副本”和“切片”都指向同一个底层数组。

func main() {
    slice := []string{"a", "b", "c"}

    fmt.Println(slice)
    //Go is still passing by value here, but the value passed is a reference
    // i.e. the copied value still points to the same underlying array
    updateSlice(slice)
    fmt.Println(slice)
}

如果您试图将其他语言(如 Javascript 或 Ruby)中的 slice 函数与 Go 中的 Slice 进行比较,请不要(提及这一点,因为我在学习 Go 时就这样做了)。

再澄清一点,当您执行slice[0] = "x" 时,您并没有修改切片;您正在修改 slice 引用的底层数组。

【讨论】:

  • 很有趣,所以如果我没看错的话,将切片的引用传递给像这样updateSlice(&slice) 的函数几乎是零意义?
  • 我不是 100% 确定,但我认为如果你通过 &slice,它可能会稍微节省内存,因为 Go 不必创建该引用的副本。
猜你喜欢
  • 2019-02-27
  • 2018-02-20
  • 2016-10-19
  • 2021-12-11
  • 1970-01-01
  • 1970-01-01
  • 2021-05-21
  • 1970-01-01
  • 2020-06-07
相关资源
最近更新 更多