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

本文翻译自:What is an idiomatic way of representing enums in Go?

I'm trying to represent a simplified chromosome, which consists of N bases, each of which can only be one of {A, C, T, G} . 我试图代表一个简化的染色体,它由N个碱基组成,每个碱基只能是{A, C, T, G}

I'd like to formalize the constraints with an enum, but I'm wondering what the most idiomatic way of emulating an enum is in Go. 我想用枚举来形式化约束,但我想知道在Go中模仿枚举的最惯用方法是什么。


#1楼

参考:https://stackoom.com/question/yWxK/在Go中表示枚举的惯用方法是什么


#2楼

Quoting from the language specs: Iota 引用语言规范: Iota

Within a constant declaration, the predeclared identifier iota represents successive untyped integer constants. 在常量声明中,预先声明的标识符iota表示连续的无类型整数常量。 It is reset to 0 whenever the reserved word const appears in the source and increments after each ConstSpec. 每当保留字const出现在源中并在每个ConstSpec之后递增时,它将复位为0。 It can be used to construct a set of related constants: 它可以用于构造一组相关的常量:

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: 在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
)

This last example exploits the implicit repetition of the last non-empty expression list. 最后一个示例利用最后一个非空表达式列表的隐式重复。


So your code might be like 所以你的代码可能就像

const (
        A = iota
        C
        T
        G
)

or 要么

type Base int

const (
        A Base = iota
        C
        T
        G
)

if you want bases to be a separate type from int. 如果你想base和int是一个单独的类型。


#3楼

Referring to the answer of jnml, you could prevent new instances of Base type by not exporting the Base type at all (ie write it lowercase). 参考jnml的答案,您可以通过根本不导出Base类型来防止Base类型的新实例(即将其写为小写)。 If needed, you may make an exportable interface that has a method that returns a base type. 如果需要,您可以创建一个可导出的接口,该接口具有返回基本类型的方法。 This interface could be used in functions from the outside that deal with Bases, ie 该接口可以用于处理Bases的外部函数,即

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
}

Inside the main package a.Baser is effectively like an enum now. 在主包内, a.Baser现在实际上就像一个枚举。 Only inside the a package you may define new instances. 只有在包中,您才可以定义新实例。


#4楼

从Go 1.4开始, go generate工具与stringer命令一起引入,使得enum易于调试和打印。


#5楼

You can make it so: 你可以这样做:

type MessageType int32

const (
    TEXT   MessageType = 0
    BINARY MessageType = 1
)

With this code compiler should check type of enum 使用此代码编译器应检查枚举的类型


#6楼

It's true that the above examples of using const and iota are the most idiomatic ways of representing primitive enums in Go. 确实,上面使用constiota例子是在Go中表示原始枚举的最惯用的方式。 But what if you're looking for a way to create a more fully-featured enum similar to the type you'd see in another language like Java or Python? 但是,如果您正在寻找一种方法来创建一个类似于您在另一种语言(如Java或Python)中看到的类型的功能更全面的枚举,该怎么办?

A very simple way to create an object that starts to look and feel like a string enum in Python would be: 创建一个开始在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)
}

Suppose you also wanted some utility methods, like Colors.List() , and Colors.Parse("red") . 假设您还需要一些实用工具方法,如Colors.List()Colors.Parse("red") And your colors were more complex and needed to be a struct. 你的颜色更复杂,需要成为一个结构。 Then you might do something a bit like this: 然后你可能会做一些像这样的事情:

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

At that point, sure it works, but you might not like how you have to repetitively define colors. 在这一点上,确定它有效,但你可能不喜欢你必须重复定义颜色。 If at this point you'd like to eliminate that, you could use tags on your struct and do some fancy reflecting to set it up, but hopefully this is enough to cover most people. 如果此时你想消除它,你可以在你的结构上使用标签并做一些反思来设置它,但希望这足以覆盖大多数人。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值