Go没有工会。但工会在许多地方都是必要的。 XML过度使用了联合或选择类型。我试图找出,这是解决失踪工会的首选方法。作为一个例子,我试图为非终端编写Go代码 Misc
在里面 XML标准 这可以是一个 评论, 一个 处理指令 要么 白色空间。
编写三种基本类型的代码非常简单。它们映射到字符数组和结构。
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}
}
为了能够测试union的内容,有必要编写三个谓词:
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
因为你似乎在问,因为你想要类型安全,我首先会争辩你的初始
解决方案已经不安全了
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的函数。对象并在以后做出决定
你真正想要处理的这些功能(评论,说明......)
如果你想模仿工会,那么你写它的方式就是我所知道的方式。
我认为这些代码量可能会减少,例如我个人认为不保障 type Misc
反对包含“非法”的东西真的很有用:简单 type Misc interface{}
会这样做,还是?
这样你就可以省去构造者和所有人 Is{Comment,ProcessingInstruction,WhiteSpace}
方法归结为类型开关
switch m := misc.(type) {
Comment: fmt.Println(m)
...
default: panic()
}
这是什么包编码/ xml与Token。
因为你似乎在问,因为你想要类型安全,我首先会争辩你的初始
解决方案已经不安全了
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的函数。对象并在以后做出决定
你真正想要处理的这些功能(评论,说明......)
如果你想模仿工会,那么你写它的方式就是我所知道的方式。
我认为这些代码量可能会减少,例如我个人认为不保障 type Misc
反对包含“非法”的东西真的很有用:简单 type Misc interface{}
会这样做,还是?
这样你就可以省去构造者和所有人 Is{Comment,ProcessingInstruction,WhiteSpace}
方法归结为类型开关
switch m := misc.(type) {
Comment: fmt.Println(m)
...
default: panic()
}
这是什么包编码/ xml与Token。
我不确定你理解你的问题。 “简单”的方法就像带有接口{}的encoding / xml包。如果您不想使用接口,那么您可以像您一样做。
但是,正如您所说,Go是一种打字语言,因此应该用于打字需求。
如果你有一个结构化的XML,那么Go可能非常合适,但你需要编写你的模式。如果你想要一个可变参数模式(一个给定的字段可以有多种类型),那么使用非类型语言可能会更好。
非常有用的json工具,可以轻松地为xml重写:
http://mholt.github.io/json-to-go/
你给了一个json输入,它给你准确的Go结构。您可以有多种类型,但您需要知道哪个字段具有哪种类型。如果你不这样做,你需要使用反射,确实你失去了Go的很多兴趣。
TL; DR 你不需要工会, interface{}
更好地解决了这个问题
C中的联合用于访问特殊内存/硬件。他们也 颠覆 类型系统。 Go没有语言原语访问特殊的内存/硬件,它也避开了 volatile
和位字段出于同样的原因。
在C / C ++中,联合也可用于真正的低级优化/位打包。权衡:牺牲类型系统并增加复杂性,有利于节省一些比特。这当然伴随着有关优化的所有警告。
Imagine Go有一个原生联盟类型。代码怎么会更好?用这个重写代码:
// pretend this struct was a union
type MiscUnion struct {
c *Comment
pi *ProcessingInstruction
ws *WhiteSpace
}
即使有内置联盟访问成员 MiscUnion
需要某种运行时检查。所以使用界面并没有变得更糟。可以说是 interface
因为运行时类型检查是内置的(不可能出错)并且具有非常好的语法来处理它,所以是优越的。
联合类型的一个优点是静态类型检查,以确保只放入适当的具体类型 Misc
。解决这个问题的Go方法是“New ...”函数,例如 MiscComment
, MiscProcessingInstruction
, MiscWhiteSpace
。
这是一个清理过的示例 interface{}
和 New*
功能: http://play.golang.org/p/d5bC8mZAB_