如何在Go中初始化一个组合结构体?

34

假设我有一个结构体,其中嵌入了另一个结构体。

type Base struct {
    ID string
}

type Child struct {
    Base
    a int
    b int
}

当我去初始化 Child 时,我不能直接初始化 ID 字段。

// unknown field 'ID' in struct literal of type Child
child := Child{ ID: id, a: a, b: b }

我必须单独初始化ID字段。

child := Child{ a: 23, b: 42 }
child.ID = "foo"

这似乎违反了封装性。Child的用户必须知道ID字段有所不同。如果我稍后将一个公共字段移动到嵌入式结构中,那可能会破坏初始化。

我可以为每个结构编写NewFoo()方法,并希望每个人都使用它,但是否有一种安全地使用带有嵌入式结构的结构文本方式,而不会揭示某些字段被嵌入?或者我在这里应用了错误的模式?


我真的觉得应该在GitHub上提一个问题。我觉得对于getter方法的语法糖(在@CeriseLimón的回答中提到)也应该同样适用于setter方法。现在的方式不仅让代码变得丑陋,而且要求类的使用者对继承/层次结构非常熟悉才能使用它。 - KOGI
1个回答

54

使用嵌套的复合字面值在单个表达式中初始化一个值:

child := Child{Base: Base{ID: id}, a: a, b: b}

Go issue 9859建议修改组合字面量与嵌入类型字段访问的一致性。这个更改将允许问题中的Child{ ID: id, a: a, b: b }表达式。

嵌入类型在提供功能上不具备封装性,意味着该特性并没有限制对嵌入类型的直接访问。应用程序可以直接访问child.Base.ID,除了使用child.ID之外。


11
“child.ID”隐藏了“ID”被嵌入的事实,但初始化程序却没有?这是一个奇怪的疏忽。如果我想要初始化封装,我需要编写自己的“New”函数吗? - Schwern
4
嵌套字段的场地推广是语法糖。该功能不提供封装。 - Charlie Tumahai
为什么你说它没有提供封装性? - Schwern
9
我认为Schwern的观点是,语法糖存在于“getter”中,但不存在于初始化器中。这是不一致的。 - KOGI

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接