结构体的值接收者

Value receiver of struct

有人可以向我解释为什么 r.a 的输出是空的,因为我在列表中添加了值 2 吗?

package main

import (
    "fmt"
)

func main() {
    var r R
    r.b = make(map[int]int)

    r.add()
    fmt.Println(r) // outputs {[] map[2:2]}
}

type R struct {
    a []int
    b map[int]int
}

func (r R) add()  {
    r.a = append(r.a, 2)
    r.b[2] = 2
}

围棋之旅的一小段摘录指出:

Methods with pointer receivers can modify the value to which the receiver points [...]. Since methods often need to modify their receiver, pointer receivers are more common than value receivers.

为什么 r.b 显示正确,而 r.a 根本没有修改?

正如我在下面的回答中所述,您的 add() 方法是一个价值接受者。因此,它将采用您初始化的结构(即 r),复制它,然后相应地修改它。因为您在 main() 函数中在 r.b 下初始化了一个新地图,所以这里只复制了对该地图的引用,而不是整个地图。因此,在地图上的操作有效,但在切片 r.a 上无效。但是为什么 r.a 根本没有改变呢?这是因为位于 add() 方法中的 append() 在您的 a 属性 下存储了一个新的切片 header 并且指向了不同的部分底层数组。最后,您的值接收方方法 add() 复制了 r,在 属性 a 下设置了一个新的切片 header,并没有改变原来的结构 r,已在 main() 函数中定义,因为它是通过值接收方方法 add().

复制的

在你的例子中,add() 方法是一个所谓的值接收方法,它不能对你定义的结构 r 直接位于 main() 函数中进行任何操作,而是复制它然后进行操作。因此,你需要把你的 add() 方法变成一个指针接收方法,就像这样:

func (r *R) add()  {
    r.a = append(r.a, 2)
    r.b[2] = 2
}

现在该方法正在获取在 main() 函数中启动的结构 r 的实际引用,并相应地对其进行修改。

如果不将您的 add() 方法更改为指针接收器,它如何工作?

您只需要 return 在您的 add() 方法中复制结构,如下所示:

package main

import (
    "fmt"
)

func main() {
    var r R
    r.b = make(map[int]int)
    fmt.Println(r.add()) // outputs {[2] map[2:2]}
}

type R struct {
    a []int
    b map[int]int
}

func (r R) add() R {
    r.a = append(r.a, 2)
    r.b[2] = 2
    return r
}