在Go中表示枚举的惯用方法是什么?

What is an idiomatic way of representing enums in Go?

我试图表示一个简化的染色体,它由n个碱基组成,每个碱基只能是{A, C, T, G}中的一个。

我想用枚举形式化约束,但我想知道模仿枚举的最惯用方法是什么。


引证:将从语言规格

Within a constant declaration, the predeclared identifier iota represents successive untyped integer constants. It is reset to 0 whenever the reserved word const appears in the source and increments after each ConstSpec. It can be used to construct a set of related constants:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
const (  // iota is reset to 0
        c0 = iota  // c0 == 0
        c1 = iota  // c1 == 1
        c2 = iota  // c2 == 2
)

const (
        a = 1 << iota  // a == 1 (iota has been reset)
        b = 1 << iota  // b == 2
        c = 1 << iota  // c == 4
)

const (
        u         = iota * 42  // u == 0     (untyped integer constant)
        v float64 = iota * 42  // v == 42.0  (float64 constant)
        w         = iota * 42  // w == 84    (untyped integer constant)
)

const x = iota  // x == 0 (iota has been reset)
const y = iota  // y == 0 (iota has been reset)

Within an ExpressionList, the value of each iota is the same because it is only incremented after each ConstSpec:

1
2
3
4
5
6
const (
        bit0, mask0 = 1 << iota, 1<<iota - 1  // bit0 == 1, mask0 == 0
        bit1, mask1                           // bit1 == 2, mask1 == 1
        _, _                                  // skips iota == 2
        bit3, mask3                           // bit3 == 8, mask3 == 7
)

This last example exploits the implicit repetition of the last non-empty expression list.

那么你的代码可能是样

1
2
3
4
5
6
const (
        A = iota
        C
        T
        G
)

1
2
3
4
5
6
7
8
type Base int

const (
        A Base = iota
        C
        T
        G
)

如果你想使用一个单独的类型是int。


指酒店在jnml应答新的实例,你可以防止由输出基地,基地型困难型(IU写它在所有小写)。如果需要,你可以作出exportable接口,有一个方法返回a库类型。这个接口可以被用在函数的外面是在处理基地。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package a

type base int

const (
    A base = iota
    C
    T
    G
)


type Baser interface {
    Base() base
}

// every base must fulfill the Baser interface
func(b base) Base() base {
    return b
}


func(b base) OtherMethod()  {
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package main

import"a"

// func from the outside that handles a.base via a.Baser
// since a.base is not exported, only exported bases that are created within package a may be used, like a.A, a.C, a.T. and a.G
func HandleBasers(b a.Baser) {
    base := b.Base()
    base.OtherMethod()
}


// func from the outside that returns a.A or a.C, depending of condition
func AorC(condition bool) a.Baser {
    if condition {
       return a.A
    }
    return a.C
}

在主包a.Baser像现在是有效的枚举。你可以只在A包定义的新实例。


为1.4),已在go generate工具介绍与stringer命令让您可以打印可调试和枚举。


你可以这样做:

1
2
3
4
5
6
type MessageType int32

const (
    TEXT   MessageType = 0
    BINARY MessageType = 1
)

这一类型的枚举代码编译器不检查


这是真的,上面的例子是使用constiota最原始的方式在一idiomatic枚举的CRP。但如果你在寻找一种方式来创建一个全功能的枚举类型类似于你在一个湖泊或Python语言的Java类?

一个非常简单的方法来创建一个对象的外观和感觉像一起飞在Python字符串的枚举类型是:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package main

import (
   "fmt"
)

var Colors = newColorRegistry()

func newColorRegistry() *colorRegistry {
    return &colorRegistry{
        Red:  "red",
        Green:"green",
        Blue: "blue",
    }
}

type colorRegistry struct {
    Red   string
    Green string
    Blue  string
}

func main() {
    fmt.Println(Colors.Red)
}

想你想的一些实用方法,样Colors.List()Colors.Parse("red")。和你所需要的是更多的颜色和复杂的结构。然后你会做这样的事:一位

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
package main

import (
   "errors"
   "fmt"
)

var Colors = newColorRegistry()

type Color struct {
    StringRepresentation string
    Hex                  string
}

func (c *Color) String() string {
    return c.StringRepresentation
}

func newColorRegistry() *colorRegistry {

    red := &Color{"red","F00"}
    green := &Color{"green","0F0"}
    blue := &Color{"blue","00F"}

    return &colorRegistry{
        Red:    red,
        Green:  green,
        Blue:   blue,
        colors: []*Color{red, green, blue},
    }
}

type colorRegistry struct {
    Red   *Color
    Green *Color
    Blue  *Color

    colors []*Color
}

func (c *colorRegistry) List() []*Color {
    return c.colors
}

func (c *colorRegistry) Parse(s string) (*Color, error) {
    for _, color := range c.List() {
        if color.String() == s {
            return color, nil
        }
    }
    return nil, errors.New("couldn't find it")
}

func main() {
    fmt.Printf("%s
", Colors.List())
}

在那点上,知道它,但你可能不喜欢你要repetitively定义的颜色。在这一点,如果你喜欢,你可以消除使用的标签,在你做一些漂亮的结构和它的反射到集,但希望这是足以覆盖大多数的人。


我知道我们有很多很好的答案在这里。但是,我只是想说我所用的方式enumerated类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
package main

import"fmt"

type Enum interface {
    name() string
    ordinal() int
    values() *[]string
}

type GenderType uint

const (
    MALE = iota
    FEMALE
)

var genderTypeStrings = []string{
   "MALE",
   "FEMALE",
}

func (gt GenderType) name() string {
    return genderTypeStrings[gt]
}

func (gt GenderType) ordinal() int {
    return int(gt)
}

func (gt GenderType) values() *[]string {
    return &genderTypeStrings
}

func main() {
    var ds GenderType = MALE
    fmt.Printf("The Gender is %s
", ds.name())
}

这是由一个idiomatic远的方式,我们可以创建和使用enumerated类型中去。

编辑:

另一种方式使用的常量添加到使用enumerate

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
package main

import (
   "fmt"
)

const (
    // UNSPECIFIED logs nothing
    UNSPECIFIED Level = iota // 0 :
    // TRACE logs everything
    TRACE // 1
    // INFO logs Info, Warnings and Errors
    INFO // 2
    // WARNING logs Warning and Errors
    WARNING // 3
    // ERROR just logs Errors
    ERROR // 4
)

// Level holds the log level.
type Level int

func SetLogLevel(level Level) {
    switch level {
    case TRACE:
        fmt.Println("trace")
        return

    case INFO:
        fmt.Println("info")
        return

    case WARNING:
        fmt.Println("warning")
        return
    case ERROR:
        fmt.Println("error")
        return

    default:
        fmt.Println("default")
        return

    }
}

func main() {

    SetLogLevel(INFO)

}