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

我想用枚举形式化约束,但我想知道在Go中模拟枚举的最惯用的方式是什么。


当前回答

你可以这样做:

type MessageType int32

const (
    TEXT   MessageType = 0
    BINARY MessageType = 1
)

使用此代码,编译器应该检查枚举类型

其他回答

引用语言规范:Iota

在常量声明中,预先声明的标识符iota表示连续的无类型整型常量。当保留字const出现在源代码中时,它被重置为0,并且在每个ConstSpec之后递增。它可以用来构造一组相关常数:

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)

在ExpressionList中,每个iota的值是相同的,因为它只在每个ConstSpec之后递增:

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
)

最后一个示例利用了最后一个非空表达式列表的隐式重复。


你的代码可能是这样的

const (
        A = iota
        C
        T
        G
)

or

type Base int

const (
        A Base = iota
        C
        T
        G
)

如果你想让base是一个独立于int的类型。

这是在golang中实现enum的安全方法:

package main

import (
    "fmt"
)

const (
    MALE   = _gender(1)
    FEMALE = _gender(2)
    RED    = _color("RED")
    GREEN  = _color("GREEN")
    BLUE   = _color("BLUE")
)

type Gender interface {
    _isGender()
    Value() int
}

type _gender int

func (_gender) _isGender() {}

func (_g _gender) Value() int {
    return int(_g)
}

type Color interface {
    _isColor()
    Value() string
}

type _color string

func (_color) _isColor() {}

func (_c _color) Value() string {
    return string(_c)
}

func main() {
    genders := []Gender{MALE, FEMALE}
    colors := []Color{RED, GREEN, BLUE}
    fmt.Println("Colors =", colors)
    fmt.Println("Genders =", genders)
}

输出:

Colors = [RED GREEN BLUE]
Genders = [1 2]

参考jnml的答案,您可以通过根本不导出Base类型来防止创建Base类型的新实例(即将其写成小写)。如果需要,您可以创建一个具有返回基类型的方法的可导出接口。这个接口可以用在处理base的外部函数中。

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

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.b eser现在实际上就像一个枚举。 只有在a包中才能定义新实例。

对于这样的用例,使用字符串常量可能很有用,这样就可以将其封送到JSON字符串中。在下例中,[]碱基{A,C,G,T}将被编组为["腺嘌呤","胞嘧啶","鸟嘌呤","胸腺嘧啶"]。

type Base string

const (
    A Base = "adenine"
    C      = "cytosine"
    G      = "guanine"
    T      = "thymine"
)

当使用iota时,值被封送成整数。在下面的例子中,[]基数{A,C,G,T}将被封送到[0,1,2,3]。

type Base int

const (
    A Base = iota
    C
    G
    T
)

下面是一个比较两种方法的例子:

https://play.golang.org/p/VvkcWvv-Tvj

重构https://stackoverflow.com/a/17989915/863651,使其更具可读性:

package SampleEnum

type EFoo int

const (
    A EFoo = iota
    C
    T
    G
)

type IEFoo interface {
    Get() EFoo
}

func(e EFoo) Get() EFoo { // every EFoo must fulfill the IEFoo interface
    return e
}

func(e EFoo) otherMethod()  { // "private"
    //some logic
}