【发布时间】:2014-02-28 11:25:38
【问题描述】:
Go has no unions。但在许多地方工会是必要的。 XML 过度使用联合或选择类型。我试图找出,这是解决失踪工会的首选方法。例如,我尝试在XML standard 中为非终端Misc 编写Go 代码,它可以是comment、processing instruction 或white space。
为这三种基本类型编写代码非常简单。它们映射到字符数组和结构。
type Comment Chars
type ProcessingInstruction struct {
Target *Chars
Data *Chars
}
type WhiteSpace Chars
但是当我完成联合的代码时,它变得非常臃肿,包含许多冗余函数。显然必须有一个容器结构。
type Misc struct {
value interface {}
}
为了确保容器只包含三种允许的类型,我将值设为私有,并且必须为每种类型编写一个构造函数。
func MiscComment(c *Comment) *Misc {
return &Misc{c}
}
func MiscProcessingInstruction (pi *ProcessingInstruction) *Misc {
return &Misc{pi}
}
func MiscWhiteSpace (ws *WhiteSpace) *Misc {
return &Misc{ws}
}
为了能够测试联合的内容,有必要编写三个谓词:
func (m Misc) IsComment () bool {
_, itis := m.value.(*Comment)
return itis
}
func (m Misc) IsProcessingInstruction () bool {
_, itis := m.value.(*ProcessingInstruction)
return itis
}
func (m Misc) IsWhiteSpace () bool {
_, itis := m.value.(*WhiteSpace)
return itis
}
为了获得正确类型的元素,需要编写三个 getter。
func (m Misc) Comment () *Comment {
return m.value.(*Comment)
}
func (m Misc) ProcessingInstruction () *ProcessingInstruction {
return m.value.(*ProcessingInstruction)
}
func (m Misc) WhiteSpace () *WhiteSpace {
return m.value.(*WhiteSpace)
}
在此之后,我能够创建 Misc 类型的数组并使用它:
func main () {
miscs := []*Misc{
MiscComment((*Comment)(NewChars("comment"))),
MiscProcessingInstruction(&ProcessingInstruction{
NewChars("target"),
NewChars("data")}),
MiscWhiteSpace((*WhiteSpace)(NewChars(" \n")))}
for _, misc := range miscs {
if (misc.IsComment()) {
fmt.Println ((*Chars)(misc.Comment()))
} else if (misc.IsProcessingInstruction()) {
fmt.Println (*misc.ProcessingInstruction())
} else if (misc.IsWhiteSpace()) {
fmt.Println ((*Chars)(misc.WhiteSpace()))
} else {
panic ("invalid misc");
}
}
}
您会看到很多代码看起来几乎相同。任何其他工会也是如此。所以我的问题是:有什么方法可以简化 Go 中处理联合的方式?
Go 声称通过removing redundancy 简化了编程工作。但我认为上面的例子正好相反。我错过了什么吗?
这里是完整的例子:http://play.golang.org/p/Zv8rYX-aFr
【问题讨论】: