Go没有工会。但是工会在很多地方都是必要的。XML过度使用联合或选择类型。我试图找出答案,这是解决缺少的工会的首选方法。作为一个例子,我试图写Go代码对于非终端Misc在XML标准,其可以是一个注释,一个处理指令或白空间。
Misc
为这三种基本类型编写代码非常简单。它们映射到字符数组和结构。
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提出的类型开关相比,该解决方案没有任何好处。
IsComment
由于要对代码进行分组,因此可以编写一个确定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() {}
这样,您可以编写仅处理杂项的函数。对象并稍后决定要在这些函数中真正要处理的内容(注释,说明等)。
如果您想模仿工会,那么据我所知,这是您写作的方式。