结构体的值接收者
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
}
有人可以向我解释为什么 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
}