来自嵌入式类型的复合文字和字段

Composite literal and fields from an embedded type

我正在编写一个示例程序来回答这里关于 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

是否可以在静态初始值设定项中设置嵌入类型的字段值?如何?对我来说,这似乎是一个编译器错误;如果我面前没有资源并且熟悉类型,我会用头撞墙说 "clearly FName exists on B what is the compiler saying!?!?!".

快速抢占典型答案我知道最接近工作的语法是 b := &B{A{FName:"evan", LName:"mcdonnal"}} 但我认为该语法在概念上与嵌入相矛盾,因此如果它是唯一的选择我会感到失望。如果这是唯一的方法,它是 Go 编译器的缺点,还是实际上存在一个理论上的限制,会阻止编译器解释我的非工作示例中的语法?

这不是编译器错误,而是设计决定。语言规范只是指出:

Promoted fields act like ordinary fields of a struct except that they cannot be used as field names in composite literals of the struct.

我想这背后的原因是为了避免歧义。使用选择器时有一些规则可以解决名称冲突,并且它们必须很复杂才能允许您的建议。最重要的是,如果您在嵌入类型的结构文字中使用嵌入结构的现有实例,则可能会产生歧义。

编辑:这是一个示例,其中这种方法可能适得其反:

考虑一种情况,其中 A 嵌入 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 }  ?

它打破了初始化顺序与字段名称的复合文字无关的假设。