一尘不染

Go中工会的最佳实践

go

Go没有工会。但是工会在很多地方都是必要的。XML过度使用联合或选择类型。我试图找出答案,这是解决缺少的工会的首选方法。作为一个例子,我试图写Go代码对于非终端MiscXML标准,其可以是一个注释,一个处理指令白空间

为这三种基本类型编写代码非常简单。它们映射到字符数组和结构。

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


阅读 263

收藏
2020-07-02

共1个答案

一尘不染

似乎您在问这是因为您想要类型安全,所以我首先认为您的初始解决方案已经不安全了

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() {}

这样,您可以编写仅处理杂项的函数。对象并稍后决定要在这些函数中真正要处理的内容(注释,说明等)。

如果您想模仿工会,那么据我所知,这是您写作的方式。

2020-07-02