Go编程语言中的struct的值接收器?

时间:2018-11-27 21:34:11

标签: pointers go receiver

有人可以向我解释为什么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
}

1 个答案:

答案 0 :(得分:1)

“围棋之旅”的简短摘录指出:

  

带有指针接收器的方法可以将值修改为   接收点[...]。由于方法通常需要修改其   接收器,指针接收器比值接收器更常见。

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

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

在您的情况下,add()方法是所谓的值接收器方法,它无法直接对位于r函数中的已定义结构main()进行任何操作,但可以对其进行复制并执行之后的操作。因此,您需要将add()方法转换为指针接收器方法,如下所示:

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

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

如何在不将您的add()方法更改为指针接收器的情况下工作?

您只需要在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
}