dpr26232 2014-02-04 13:06
浏览 57
已采纳

Go中工会的最佳实践

Go has no unions. But unions are necessary in many places. XML makes excessive use of unions or choice types. I tried to find out, which is the preferred way to work around the missing unions. As an example I tried to write Go code for the non terminal Misc in the XML standard which can be either a comment, a processing instruction or white space.

Writing code for the three base types is quite simple. They map to character arrays and a struct.

type Comment Chars

type ProcessingInstruction struct {
    Target *Chars
    Data *Chars
}

type WhiteSpace Chars

But when I finished the code for the union, it got quite bloated with many redundant functions. Obviously there must be a container struct.

type Misc struct {
    value interface {}
}

In order to make sure that the container holds only the three allowed types I made the value private and I had to write for each type a constructor.

func MiscComment(c *Comment) *Misc {
    return &Misc{c}
}

func MiscProcessingInstruction (pi *ProcessingInstruction) *Misc {
    return &Misc{pi}
}

func MiscWhiteSpace (ws *WhiteSpace) *Misc {
    return &Misc{ws}
}

In order to be able to test the contents of the union it was necessary to write three predicates:

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
}

And in order to get the correctly typed elements it was necessary to write three getters.

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

After this I was able to create an array of Misc types and use it:

func main () {

    miscs := []*Misc{
        MiscComment((*Comment)(NewChars("comment"))),
        MiscProcessingInstruction(&ProcessingInstruction{
            NewChars("target"),
            NewChars("data")}),
        MiscWhiteSpace((*WhiteSpace)(NewChars(" 
")))}

    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");
        }
    }
}

You see there is much code looking almost the same. And it will be the same for any other union. So my question is: Is there any way to simplify the way to deal with unions in Go?

Go claims to simplify programing work by removing redundancy. But I think the above example shows the exact opposite. Did I miss anything?

Here is the complete example: http://play.golang.org/p/Zv8rYX-aFr

  • 写回答

4条回答 默认 最新

  • douying1119 2014-02-05 01:43
    关注

    As it seems that you're asking because you want type safety, I would firstly argue that your initial solution is already unsafe as you have

    func (m Misc) Comment () *Comment {
        return m.value.(*Comment)
    }
    

    which will panic if you haven't checked IsComment before. Therefore this solution has no benefits over a type switch as proposed by Volker.

    Since you want to group your code you could write a function that determines what a Misc element is:

    func IsMisc(v {}interface) bool {
        switch v.(type) {
            case Comment: return true
            // ...
        }
    }
    

    That, however, would bring you no compiler type checking either.

    If you want to be able to identify something as Misc by the compiler then you should consider creating an interface that marks something as Misc:

    type Misc interface {
        ImplementsMisc()
    }
    
    type Comment Chars
    func (c Comment) ImplementsMisc() {}
    
    type ProcessingInstruction
    func (p ProcessingInstruction) ImplementsMisc() {}
    

    This way you could write functions that are only handling misc. objects and get decide later what you really want to handle (Comments, instructions, ...) in these functions.

    If you want to mimic unions then the way you wrote it is the way to go as far as I know.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(3条)

报告相同问题?

悬赏问题

  • ¥15 在现有系统基础上增加功能
  • ¥15 远程桌面文档内容复制粘贴,格式会变化
  • ¥15 关于#java#的问题:找一份能快速看完mooc视频的代码
  • ¥15 这种微信登录授权 谁可以做啊
  • ¥15 请问我该如何添加自己的数据去运行蚁群算法代码
  • ¥20 用HslCommunication 连接欧姆龙 plc有时会连接失败。报异常为“未知错误”
  • ¥15 网络设备配置与管理这个该怎么弄
  • ¥20 机器学习能否像多层线性模型一样处理嵌套数据
  • ¥20 西门子S7-Graph,S7-300,梯形图
  • ¥50 用易语言http 访问不了网页