在Go中枚举常量的最佳方法

时间:2017-02-02 19:58:28

标签: python postgresql go enums idiomatic

我开始学习其他语言。 Go有一个非常elegant way of creating constants的数字值,如:

const (
    _      = iota    // 0 and is skipped
    Sunday           // 1
    Monday           // 2
    ...
)

这很容易编写,但是它很容易维护吗?例如,如果您突然在当前之间插入新值,则后续所有值都将更改其值。它很难找到,只有严格的差异读取才能揭示它。或其他部分的错误。如何使用名称提取这些值并在程序的其他部分或数据库中使用? 例如,对于PostgreSQL,我可以定义:

CREATE TYPE color AS ENUM ('', 'Sunday', 'Monday');

只是为了说明一个想法。例如,Python has Enum类型:

from enum import Enum
class Color(Enum):
    RED = 1
    GREEN = 2
    BLUE = 3

然后您可以像Color.RED一样使用它。接下来我可以采用所有值:

list(Color)
[<Color.RED: 1>, <Color.BLUE: 2>, <Color.GREEN: 3>]

这让我能够内省&#34;模块化并在数据库中创建易于阅读的枚举。例如,对于PostgreSQL,我可以定义:

CREATE TYPE color AS ENUM ('RED', 'GREEN', 'BLUE');

我怎么能:

  1. 反映golang常量名称?
  2. 制作不能漂移其值的防错常数?只能手动修复它们吗?
  3. 可能会有更好的方法吗?
  4. 感谢。

3 个答案:

答案 0 :(得分:3)

1)您可以使用stringer生成名称https://godoc.org/golang.org/x/tools/cmd/stringer

2)不确定你是什么意思?大多数语言都允许你漂移值,你应该总是添加到列表的末尾,如果你想让数字保持不变,或者像在python中你可以明确地将每个值设置为数字而不是使用iota。

3)不是真的,在golang中,enums并不是很好。

答案 1 :(得分:2)

只是一个建议,但在你的情况下可能会有所帮助:我发现如果很明显值看起来像位掩码,那么常量不太可能在以后更改/破坏,你可以在像这样:

const (
    Red   = 1 << iota
    Green
    Blue
) // values = 1, 2, 4

而且,即使它不是最漂亮的声明,你也可以包括掩码常量

const (
    Red, RedMask = 1 << iota, 1<< iota - 1 // Red = 1, RedMask = 0
    Green, GreenMask                       // Green = 2, mask = 1
    Blue, BlueMask                         // 4, 3
    RGB, RGBMask                           // 8, 7
)

这与这些常量的指定type结合使用可能很有用:

type ColourConst int
const (
    Red, RMask ColourConst = 1 << iota, 1 << iota-1
    // ...
    _, All
)

// something like this (untested, might not be correct)
func (c ColourConst) validate() error {
    mask := int(c) & (-1 * int(c))
    if mask != int(c) {
        return errors.New("Colour is not a single bit value")
    }
    if s := c & All; s != c {
        return errors.New("Colour is not in range")
    }
}

我知道一周中的日子不太可能被用作位掩码,但它使人们不太可能破坏代码。至少,它传达了常数的顺序很重要,这是IMO iota的作用。

答案 2 :(得分:0)

解。 有优秀的模块Enumer和Enumelinter