Go中工会的最佳实践
Go没有工会。但是工会在很多地方都是必要的。XML过度使用联合或选择类型。我试图找出答案,这是解决缺少的工会的首选方法。作为一个例子,我试图写Go代码对于非终端Misc
在XML标准,其可以是一个注释,一个处理指令或白空间。
为这三种基本类型编写代码非常简单。它们映射到字符数组和结构。
type Comment Chars
type ProcessingInstruction struct {
Target *Chars
Data *Chars
}
type WhiteSpace Chars
但是,当我完成联合的代码时,它变得with肿了许多冗余功能。显然必须有一个容器结构。
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声称通过消除冗余来简化编程工作。但是我认为上面的例子显示了完全相反的情况。我有想念吗?
这是完整的示例:http :
//play.golang.org/p/Zv8rYX-aFr
-
似乎您在问这是因为您想要类型安全,所以我首先认为您的初始解决方案已经不安全了
func (m Misc) Comment () *Comment { return m.value.(*Comment) }
如果您之前没有检查
IsComment
过,将会感到恐慌。因此,与Volker提出的类型开关相比,该解决方案没有任何好处。由于要对代码进行分组,因此可以编写一个确定
Misc
元素是什么的函数:func IsMisc(v {}interface) bool { switch v.(type) { case Comment: return true // ... } }
但是,那也不会给您带来编译器类型检查。
如果您希望能够
Misc
由编译器识别某些内容,则应考虑创建一个将某些内容标记为的接口Misc
:type Misc interface { ImplementsMisc() } type Comment Chars func (c Comment) ImplementsMisc() {} type ProcessingInstruction func (p ProcessingInstruction) ImplementsMisc() {}
这样,您可以编写仅处理杂项的函数。对象并稍后决定要在这些函数中真正要处理的内容(注释,说明等)。
如果您想模仿工会,那么据我所知,这是您写作的方式。