Go没有工会。但在许多地方,工会是必要的。XML过度使用联合或选择类型。我试着找出答案,这是解决工会问题的首选方法。例如,我试图为XML标准中的非终端XML标准编写Go代码,该代码可以是评论、处理指令或空白区。
为这三种基本类型编写代码非常简单。它们映射到字符数组和结构。
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声称简化了消除冗余的编程工作。但我认为上面的例子正好相反。我错过什么了吗?
下面是完整的示例:http://play.golang.org/p/Zv8rYX-aFr
发布于 2014-02-05 01:43:26
就像你要求的那样,因为你想要类型安全,我首先要说的是你最初的解决方案已经不安全了
func (m Misc) Comment () *Comment {
return m.value.(*Comment)
}如果您以前没有检查过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() {}这样,您就可以编写只处理misc的函数。对象,然后再决定真正要处理的内容(注释、说明、.)。在这些职能中。
如果你想模仿工会,那么你的写作方式就是我所知道的。
发布于 2014-02-04 14:20:30
我认为这样的代码数量可能会减少,例如,我个人并不认为保护type Misc不包含“非法”的东西真的有帮助:一个简单的type Misc interface{}就可以了,或者呢?
这样,就可以节省构造函数和所有Is{Comment,ProcessingInstruction,WhiteSpace}方法,从而简化为类型切换。
switch m := misc.(type) {
Comment: fmt.Println(m)
...
default: panic()
}这就是包编码/xml对令牌所做的事情。
发布于 2014-02-04 23:34:23
我不太明白你的问题。这样做的‘容易’方式将类似于带有接口{}的编码/xml包。如果您不想使用接口,那么您可以像以前那样做一些事情。但是,正如您所说的,Go是一种类型化语言,因此应该用于类型化需求。如果您有一个结构化XML,Go可能是一个很好的选择,但是您需要编写您的模式。如果您想要一个多样化的模式(一个给定的字段可以有多个类型),那么使用非类型化语言可能会更好。
对于json来说非常有用的工具,可以很容易地为xml:http://mholt.github.io/json-to-go/重写。
给出一个json输入,它给出确切的Go结构。您可以有多个类型,但您需要知道哪个字段具有什么类型。如果你不这样做,你需要使用反射,实际上你失去了很多的兴趣去。
https://stackoverflow.com/questions/21553398
复制相似问题