代码之家  ›  专栏  ›  技术社区  ›  kentor

替代枚举[重复]

go
  •  -1
  • kentor  · 技术社区  · 6 年前

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

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

    0 回复  |  直到 8 年前
        1
  •  688
  •   zzzz    12 年前

    引用语言规范: Iota

    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
    )
    

    type Base int
    
    const (
            A Base = iota
            C
            T
            G
    )
    

    如果你想让bases与int独立。

        2
  •  91
  •   Taavi metakeule    6 年前

    参考jnml的答案,您可以通过根本不导出基类型(即写为小写)来阻止基类型的新实例。如果需要,您可以制作一个可导出的接口,该接口具有返回基类型的方法。此接口可用于外部处理基的函数中,即。

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

        3
  •  32
  •   Azat    7 年前

    你可以做到:

    type MessageType int32
    
    const (
        TEXT   MessageType = 0
        BINARY MessageType = 1
    )
    

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

        4
  •  27
  •   Becca Petrin    7 年前

    上面的例子 const iota 是在Go中表示原始枚举的最惯用方法。但是,如果您正在寻找一种方法来创建一个功能更全面的enum,类似于在其他语言(如Java或Python)中看到的类型,该怎么办?

    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") . 你的颜色更复杂,需要一个结构。然后你可以做一些类似的事情:

    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\n", Colors.List())
    }
    

        5
  •  19
  •   Zippo    9 年前

    go generate 工具与 stringer 使枚举易于调试和打印的命令。

        6
  •  13
  •   wandermonk    6 年前

    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\n", ds.name())
    }
    

    编辑:

    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)
    
    }
    
        7
  •  6
  •   adiga    5 年前

    下面是一个例子,当有许多枚举时,它将被证明是有用的。它使用Golang中的结构,并利用面向对象的原则将它们组合在一起。添加或删除新枚举时,基础代码都不会更改。过程是:

    • enumeration items 枚举项 . 它有一个整数和字符串类型。
    • 定义 enumeration 作为一个列表 枚举项
    • 生成枚举的方法。其中包括:
      • enum.Name(index int) :返回给定索引的名称。
      • enum.Index(name string)
      • enum.Last() :返回最后一个枚举的索引和名称

    下面是一些代码:

    type EnumItem struct {
        index int
        name  string
    }
    
    type Enum struct {
        items []EnumItem
    }
    
    func (enum Enum) Name(findIndex int) string {
        for _, item := range enum.items {
            if item.index == findIndex {
                return item.name
            }
        }
        return "ID not found"
    }
    
    func (enum Enum) Index(findName string) int {
        for idx, item := range enum.items {
            if findName == item.name {
                return idx
            }
        }
        return -1
    }
    
    func (enum Enum) Last() (int, string) {
        n := len(enum.items)
        return n - 1, enum.items[n-1].name
    }
    
    var AgentTypes = Enum{[]EnumItem{{0, "StaffMember"}, {1, "Organization"}, {1, "Automated"}}}
    var AccountTypes = Enum{[]EnumItem{{0, "Basic"}, {1, "Advanced"}}}
    var FlagTypes = Enum{[]EnumItem{{0, "Custom"}, {1, "System"}}}
    
        8
  •  1
  •   Yu Huang    4 年前

    有一种使用struct命名空间的方法。

    这样做的好处是所有枚举变量都在特定的命名空间下,以避免污染。 var const

    type OrderStatusType string
    
    var OrderStatus = struct {
        APPROVED         OrderStatusType
        APPROVAL_PENDING OrderStatusType
        REJECTED         OrderStatusType
        REVISION_PENDING OrderStatusType
    }{
        APPROVED:         "approved",
        APPROVAL_PENDING: "approval pending",
        REJECTED:         "rejected",
        REVISION_PENDING: "revision pending",
    }