英文:
Function assignments of an interface of a structure pointer with a structure show different values
问题
我对代码的下一部分有点困惑:
type Tiger struct {
weight int
}
func (t Tiger) Weight() int {
return t.weight
}
type AsianTiger struct {
Tiger
}
type Tigers interface {
Weight() int
}
func main() {
t := &AsianTiger{Tiger{3}}
var i Tigers = t
f := t.Weight
g := i.Weight
t.weight = 7
fmt.Println(f(), g()) // 结果是:3 7 | 预期结果是 7 7
z := t
x := i
t.weight = 8
fmt.Println(z.Weight(), x.Weight()) // 结果是:8 8
}
有人能帮我理解一下 f := t.Weight
和 g := i.Weight
发生了什么,为什么它们显示不同的结果,而我预期它们应该是相同的,底层发生了什么?
英文:
I'm a bit confused with the next part of the code:
type Tiger struct {
weight int
}
func (t Tiger) Weight() int {
return t.weight
}
type AsianTiger struct {
Tiger
}
type Tigers interface {
Weight() int
}
func main() {
t := &AsianTiger{Tiger{3}}
var i Tigers = t
f := t.Weight
g := i.Weight
t.weight = 7
fmt.Println(f(), g()) // result is: 3 7 | expected 7 7
z := t
x := i
t.weight = 8
fmt.Println(z.Weight(), x.Weight()) // result is: 8 8
}
Could someone help me please to understand what is happening with f := t.Weight
and g := i.Weight
why did they show different results when I expected similarity, and what is happening under the hood?
答案1
得分: 5
问题/困惑的根源在于以下代码行:
f := t.Weight
g := i.Weight
这些是方法值。**方法值会将接收器保存在结果函数值中!**而你的Tiger.Weight()
方法具有值接收器(而不是指针接收器):
func (t Tiger) Weight() int {
return t.weight
}
这意味着t.Weight
将保存接收器t
,它是一个Tiger
结构体,并且连同当前的weight=3
字段一起保存。(注意:在f:= t.Weight
中,t
是一个*AsianTiger
值,但t.Weight
是从嵌入的Tiger
类型中提升的方法,所以t.Weight
实际上表示AsianTiger.Tiger.Weight()
方法,其接收器是一个Tiger
结构体值。)
另一方面,方法值i.Weight
是Tigers
接口的方法,其中包装的具体值的类型是*AsianTiger
,一个指针。因此,指针值将被保存。
接下来,你改变了权重:
t.weight = 7
这不会影响f
,因为保存的是Tiger
结构体值(接收器),它是一个副本。但这会影响g
,因为保存的接收器是Tigers
,它持有*AsianTiger
,而你改变的是指向的值(而不是指针)。
如果你添加另一行代码,你会看到:
fmt.Println(f(), g()) // 输出结果为:3 7 | 预期结果为 7 7
fmt.Println(t.Weight(), i.Weight()) // 输出结果为:7 7
这将输出(在Go Playground上尝试一下):
3 7
7 7
第二行打印的是7 7
,因为它使用的不是保存的接收器值,而是实际的t
值(以及指向t
的i
)。
你代码的剩余部分:
z := t
x := i
t.weight = 8
fmt.Println(z.Weight(), x.Weight()) // 输出结果为:8 8
在这里,z
和x
不是方法值。z
是t
的副本,它是一个指针,而x
是i
的副本,它是一个包装指针的接口值。然后你改变了指向的值(指向值的字段)。最后,你调用了z
和x
的方法,没有保存的接收器发生作用,接收器在改变之后进行评估。
英文:
The source of the problem / confusion lies in these lines:
f := t.Weight
g := i.Weight
These are method values. A method value saves the receiver in the result function value! And your Tiger.Weight()
method has value receiver (not pointer receiver):
func (t Tiger) Weight() int {
return t.weight
}
This means that t.Weight
will save the receiver t
, which is a Tiger
struct, and along with it the current weight=3
field. (Note: it's true that in f:= t.Weight
t
is an *AsianTiger
value, but t.Weight
is a promoted method from the embedded Tiger
type, so t.Weight
effectively means / denotes the AsianTiger.Tiger.Weight()
method whose receiver is a Tiger
struct value.)
The method value i.Weight
on the other hand is a method of Tigers
, the interface, and the concrete value wrapped in it is of type *AsianTiger
, a pointer. So the pointer value will be saved.
Next you change the weight:
t.weight = 7
This will not effect f
, because the Tiger
struct value (the receiver) is saved, it's a copy. This will however effect g
, because the saved receiver there is Tigers
which holds *AsianTiger
, and you change the pointed value (not the pointer).
You can see if you add another line:
fmt.Println(f(), g()) // result is: 3 7 | expected 7 7
fmt.Println(t.Weight(), i.Weight()) // result is: 7 7
This outputs (try it on the Go Playground):
3 7
7 7
The second line prints 7 7
because not a saved receiver value is used, but the actual value of t
(and i
which points to t
).
The remaining of your code:
z := t
x := i
t.weight = 8
fmt.Println(z.Weight(), x.Weight()) // result is: 8 8
Here z
and x
are not method values. z
is a copy of t
which is a pointer, and x
is a copy of i
, an interface value which wraps a pointer. And you change the pointed value (a field of a field of the pointed value). And last you call the methods of z
and x
, no saved receiver takes place, receivers are evaluated after the change.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论