嵌套结构体中提升的方法问题

huangapple go评论93阅读模式
英文:

Struct in struct embedding promoted methods question

问题

package main

import "fmt"

type type1 struct { //T
}

func (t1 type1) type1Meth1() {
	fmt.Printf("===> func (t1 type1) type1Meth1():\n Type: %T\n Value: %+v\n\n", t1, t1)
}

func (t1 *type1) type1Meth2() {
	fmt.Printf("===> func (t1 *type1) type1Meth2():\n Type: %T\n Value: %p\n Contains: %+v\n\n", t1, t1, t1)
}

func (t1 type1) type1Meth3() {
	fmt.Printf("===> func (t1 type1) type1Meth3():\n Type: %T\n Value: %+v\n", t1, t1)
}

type type2 struct { //S
	type1
}

func (t2 *type2) type1Meth3() {
	fmt.Printf("===> func (t2 *type2) type1Meth3(): Type: %T\n Value: %+v\n\n", t2, t2)
}
func main() {
	t2 := type2{}
	t2.type1Meth1() // type2包含type1的方法集
	t2.type1Meth2() // 不确定为什么这个可以工作?type2没有*type1的方法集(A)
	t2.type1Meth3() // type2包含type1的方法集。通过嵌入类型type2截取并使用*type2接收器调用
}

输出结果:

$ go run embed-struct-in-struct.go
===> func (t1 type1) type1Meth1():
 Type: main.type1
 Value: {}

===> func (t1 *type1) type1Meth2():
 Type: *main.type1
 Value: 0x116be80
 Contains: &{}

===> func (t2 *type2) type1Meth3(): Type: *main.type2
 Value: &{type1:{}}

go version
go version go1.17.2 darwin/amd64

不确定为什么在(A)中的调用可以工作?
文档中说明:嵌入方法将按照以下方式包含在结构体的方法集中:

  • 如果S包含一个嵌入字段T,则S和*S的方法集都包括具有接收器T的嵌入方法。S的方法集还包括具有接收器T的嵌入方法。

  • 如果S包含一个嵌入字段T,则S和S的方法集都包括具有接收器T或*T的嵌入方法。

英文:
package main

import "fmt"

type type1 struct { //T
}

func (t1 type1) type1Meth1() {
	fmt.Printf("==> func (t1 type1) type1Meth1():\n Type: %T\n Value: %+v\n\n", t1, t1)
}

func (t1 *type1) type1Meth2() {
	fmt.Printf("==> func (t1 *type1) type1Meth2():\n Type: %T\n Value: %p\n Contains: %+v\n\n", t1, t1, t1)
}

func (t1 type1) type1Meth3() {
	fmt.Printf("==> func (t1 type1) type1Meth3():\n Type: %T\n Value: %+v\n", t1, t1)
}

type type2 struct { //S
	type1
}

func (t2 *type2) type1Meth3() {
	fmt.Printf("==> func (t2 *type2) type1Meth3(): Type: %T\n Value: %+v\n\n", t2, t2)
}
func main() {
	t2 := type2{}
	t2.type1Meth1() // type2 contains method set of type1
	t2.type1Meth2() // not sure, why this works? type2 does not have method set of *type1 (A)
	t2.type1Meth3() // type2 contains method set of type1. intercepted by embedding type type2 and called with *type2 receiver
}

Gives me:

$ go run embed-struct-in-struct.go
==> func (t1 type1) type1Meth1():
 Type: main.type1
 Value: {}

==> func (t1 *type1) type1Meth2():
 Type: *main.type1
 Value: 0x116be80
 Contains: &{}

==> func (t2 *type2) type1Meth3(): Type: *main.type2
 Value: &{type1:{}}

go version
go version go1.17.2 darwin/amd64

Not sure why call in (A) works?
Documentation says: promoted methods are included in the method set of the struct as follows:

> Given a struct type S and a defined type T, promoted methods are included in the method set of the struct as follows:

> If S contains an embedded field T, the method sets of S and *S both include promoted methods with receiver T. The method set of *S also includes promoted methods with receiver *T.
> If S contains an embedded field *T, the method sets of S and *S both include promoted methods with receiver T or *T.

答案1

得分: 3

(A)之所以有效,是因为方法调用隐式地获取了接收者的地址。

根据问题中引用的提升规则,方法(*type1).type1Meth2()被提升为*type2

在规范的调用部分中有这样的说明:

> 如果方法集(的类型)x包含m,并且参数列表可以分配给m的参数列表,则方法调用x.m()是有效的。如果x是可寻址的,并且&x的方法集包含m,则x.m()是(&x).m()的简写形式:

表达式t2.type1Meth2()(&t2).type1Meth2()的简写形式,因为t2是可寻址的,并且type1Meth2()*type2的方法集中。

英文:

(A) works because the method call implicitly takes the address of the receiver.

The method (*type1).type1Meth2() is promoted to *type2 per the promotion rules quoted in the question.

The section of the specification on calls says:

> A method call x.m() is valid if the method set of (the type of) x contains m and the argument list can be assigned to the parameter list of m. If x is addressable and &x's method set contains m, x.m() is shorthand for (&x).m():

The expression t2.type1Meth2() is shorthand for (&t2).type1Meth2() because t2 is addressable and type1Meth2() is in the method set of *type2.

huangapple
  • 本文由 发表于 2021年11月1日 05:34:18
  • 转载请务必保留本文链接:https://go.coder-hub.com/69790774.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定