我正在研究一个示例程序来回答SO上的另一个问题,并且发现自己有点困惑于以下代码无法编译;
https://play.golang.org/p/wxBGcgfs1o
package main
import "fmt"
type A struct {
FName string
LName string
}
type B struct {
A
}
func (a *A) Print() {
fmt.Println(a.GetName())
}
func (a *A) GetName() string {
return a.FName
}
func (b *B) GetName() string {
return b.LName
}
func main() {
a := &A{FName:"evan", LName:"mcdonnal"}
b := &B{FName:"evan", LName:"mcdonnal"}
a.Print()
b.Print()
}
错误是;
/tmp/sandbox596198095/main.go:28: unknown B field 'FName' in struct literal
/tmp/sandbox596198095/main.go:28: unknown B field 'LName' in struct literal
是否可以在静态初始值设定项中设置嵌入类型的字段值?怎么样?对我来说,这似乎是一个编译器错误;如果我没有在我面前的消息来源并且熟悉类型我会在墙上敲打着说“明确FName存在于B上,编译器说什么!?!?!”。
很快,为了抢占典型答案,我知道最接近的工作语法是b := &B{A{FName:"evan", LName:"mcdonnal"}}
,但我认为这种语法在概念上与嵌入相矛盾,所以如果它是唯一的选择,我会感到失望。如果这是唯一的方法,它是Go编译器的短暂出现还是实际上存在理论上的限制会妨碍编译器解释我的非工作示例中的语法?
答案 0 :(得分:4)
它不是编译器 bug ,而是一个设计决策。语言规范只是声明:
提升字段的作用类似于结构的普通字段,除了它们不能用作结构的复合文字中的字段名称。
我猜这背后的原因是为了避免歧义。使用选择器时,有一些规则可以解决名称冲突,并且为了允许您提供的建议,它们必须很复杂。最重要的是,如果您在嵌入类型的结构文字中使用嵌入式结构的现有实例,则可能会产生歧义。
编辑:以下是这种方法适得其反的例子:
想想你有嵌入B的情况,以及你要嵌入的A的实例:
type A {
X int
}
type B {
A
}
这很简单
b := B{ X: 1 }
并推断应该做些什么。 但是,如果我们已经拥有A的实例呢?这没有意义:
a := A { X: 1 }
b := B { X: 2, A: a, }
你首先将2分配给A的零实例,然后在其上分配A的初始化实例吗?它是否与:
相同b := B { A: a, X: 2 } ?
它打破了初始化顺序与具有字段名称的复合文字无关的假设。