本文介绍了Go的工会最佳实践的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

。但工会在很多地方都是必要的。 XML会过度使用联合或选择类型。我试图找出,这是解决失踪工会的首选方法。作为一个例子,我绑定在,它可以是,或。



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

  type注释字符

类型ProcessingInstruction struct {
目标*字符
数据*字符
}

类型WhiteSpace字符

但是当我完成union的代码时,它有很多冗余函数的臃肿。显然,必须有一个容器结构。

  type Misc struct {
interface interface {}
}

为了确保容器只保留三种允许的类型,为每种类型写一个构造函数。

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

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

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

为了能够测试union的内容,有必要编写三个谓词:

  func (m Misc)IsComment()bool {
_,itis:= m.value。(* Comment)
return itis
}

func(m Misc) IsProcessingInstruction()bool {
_,itis:= m.value。(* ProcessingInstruction)
ret urn itis
}

func(m Misc)IsWhiteSpace()bool {
_,itis:= m.value。(* WhiteSpace)
return itis





$ b为了得到正确类型的元素,有必要编写三个getter。 / b>

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


func(m杂项)ProcessingInstruction()* ProcessingInstruction {
return m.value。(* ProcessingInstruction)
}

func(m杂项)WhiteSpace()* WhiteSpace {
return m.value。(* WhiteSpace)
}

在此之后,我可以创建一个 Misc 类型的数组并使用它:

<$ p $ ($ * $ b $ func main(){

miscs:= [] * Misc {
MiscComment((* Comment)(NewChars(comment))),
MiscProcessingInstruction(& ProcessingInstruction {
NewChars(target),
NewChars(data)}),
MiscWh iteSpace((* WhiteSpace)(NewChars(\ n)))}

for _,misc:= range miscs {
if(misc.IsComment()){
fmt.Println((* Chars)(misc.Comment()))
} else if(misc.IsProcessingInstruction()){
fmt.Println(* misc.ProcessingInstruction())
$ b fmt.Println((* Chars)(misc.WhiteSpace()))
} else {
panic(invalid misc)$ b $ else if(misc.IsWhiteSpace()){
fmt.Println );



$ / code $ / pre
$ b $你看到有很多代码看起来几乎一样。对于任何其他工会来说都是一样的。所以我的问题是:有没有什么办法可以简化在Go中处理工会的方式?



Go声称通过。但我认为上面的例子显示了完全相反的情况。我错过了什么?



以下是完整的示例:

解决方案

因为它看起来你在问,因为你想要类型安全,我首先会争辩说,你的初始
解决方案已经不安全,因为你有

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

如果您之前没有检查过 IsComment ,那么它会惊慌失措。因此,该解决方案与所提议的
a类型切换相比没有任何优势。



由于您想对代码进行分组,因此您可以编写一个函数来确定 Misc 元素的含义:

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

然而,这会让你没有编译器类型检查。



如果您希望编译器能够识别 Misc ,那么您应该
考虑创建一个标记为 Misc 的接口:

 类型Misc接口{
ImplementsMisc()
}

类型注释字符
func(c Comment)ImplementsMisc(){}

类型ProcessingInstruction
func(p ProcessingInstruction)ImplementsMisc(){}

通过这种方式,您可以编写仅处理misc的函数。对象,然后再决定
这些函数中你真正想要处理的内容(注释,说明,...)。

如果你想模仿工会,就我所知,你写的方式是最好的选择。


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

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

解决方案

As it seems that you're asking because you want type safety, I would firstly argue that your initialsolution 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 overa 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 laterwhat 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.

这篇关于Go的工会最佳实践的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-27 16:03