复合字面量和嵌入类型的字段

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

Composite literal and fields from an embedded type

问题

我正在为你翻译以下内容:

我正在为SO上的另一个问题编写一个示例程序,并发现以下代码无法编译:

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

是否可以在静态初始化器中设置嵌入类型的字段值?如何设置?对我来说,这似乎是一个编译器错误;如果我没有源代码,并且对类型不熟悉,我会一直在墙上撞头,说“显然B上存在FName,编译器在说什么!?!?”。

为了迅速回答,我预先防止了一些典型的答案,我知道最接近工作的语法是 b := &B{A{FName:"evan", LName:"mcdonnal"}},但在我看来,这种语法在概念上与嵌入相矛盾,如果这是唯一的选项,我会感到失望。如果这是唯一的方法,那么这是Go编译器的缺陷,还是实际上有一个理论限制,阻止编译器解释我非工作示例中的语法?

英文:

I was working on a sample program to answer another question here on SO and found myself somewhat baffled by the fact that the following code will not compile;

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()
}

The error is;

/tmp/sandbox596198095/main.go:28: unknown B field 'FName' in struct literal
/tmp/sandbox596198095/main.go:28: unknown B field 'LName' in struct literal

Is it possible to set the value of fields from an embedded type in a static initializer? How? To me this seems like a compiler bug; if I didn't have the sources in front of me and was familiar with type I would be beating my head against a wall saying "clearly FName exists on B what is the compiler saying!?!?!".

Quickly, to preempt typical answers I am aware that the closest working syntax is this b := &B{A{FName:"evan", LName:"mcdonnal"}} but that syntax is in my opinion conceptually contradictory to embedding so I would be disappointed if it is the only option. If this is the only way, is it a short coming of the Go compiler or is there actually a theoretical limitation that would prevent a compiler from interpreting the syntax in my non-working example?

答案1

得分: 4

这不是一个编译器的错误,而是一个设计决策。语言规范只是说明了:

> 提升的字段就像结构体的普通字段一样,只是不能在结构体的复合字面量中用作字段名。

我猜这背后的原因是为了避免歧义。在使用选择器时,有一些规则来解决名称冲突,如果允许你所建议的情况,这些规则将变得复杂。此外,如果在嵌入类型的结构字面量中使用现有的嵌入结构的实例,可能会产生歧义。

编辑:这里有一个可能会出现问题的例子:

想象一种情况,你有一个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 } ?

它打破了初始化顺序在带有字段名的复合字面量中是无关紧要的假设。

英文:

It's not a compiler bug but a design decision. The language spec just states:

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

I guess the reasoning behind this is to avoid ambiguity. There are a few rules to resolve name conflicts when using selectors, and they would have to be complicated in order to allow what you're suggesting. On top of that, it might create ambiguity if you're using an existing instance of an embedded struct inside a struct literal of the embedding type.

EDIT: Here's an example where this approach might backfire:

Think of a case where you have A embedding B, and an instance of A you want to embed:

type A {
   X int
}

type B {
   A
}

It's simple enough to do

b := B{ X: 1 } 

And infer what should be done.
But what if we already have an instance of A? This doesn't make sense:

a := A { X: 1 }

b := B { X: 2, A: a, } 

are you first assigning 2 to a zero instance of A and then assigning the initialized instance of A over it? And is it identical to:

b := B { A: a, X: 2 }  ?

It breaks the assumption that initialization order is irrelevant in a composite literal with field names.

huangapple
  • 本文由 发表于 2015年5月1日 06:45:56
  • 转载请务必保留本文链接:https://go.coder-hub.com/29979056.html
匿名

发表评论

匿名网友

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

确定