来自嵌入式类型的复合文字和字段
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 } ?
它打破了初始化顺序与字段名称的复合文字无关的假设。
我正在编写一个示例程序来回答这里关于 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 } ?
它打破了初始化顺序与字段名称的复合文字无关的假设。