键入有限值的安全枚举

  • 本文关键字:安全 枚举 go
  • 更新时间 :
  • 英文 :


Go中如何在有限的值范围内实现类型安全枚举?

例如,假设我想用一个简单的"大小"one_answers"颜色"来建模t恤,这两个值都是有限的,以确保我不能创建一个具有不支持值的实例。

我可以基于string声明类型SizeColor,定义有效值的枚举,以及使用它们的TShirt类型:

type Size string
const (
Small  Size = "sm"
Medium      = "md"
Large       = "lg"
// ...
)
type Color string
const (
Red   Color = "r"
Green       = "g"
Blue        = "b"
// ...
)
type TShirt struct {
Size  Size
Color Color
}
var mediumBlueShirt = TShirt{Medium, Blue}

但是,我如何确保没有创建未定义尺寸/颜色的T恤?

var doNotWant = TShirt{"OutrageouslyLarge", "ImpossibleColor"}

没有直接支持有限集枚举,但您可以使用类型系统来实现这一点:

// Exported interface 
type Size interface {
// Unexported method
isSize()
}
// unexported type
type size struct {
sz string
}
func (s size) String() string {return s.sz}
// Implement the exported interface
func (size) isSize() {}
var (
Small Size = size{"small"}
Large Size = size{"large"}
)

通过这种方式,您只能使用预先声明的值。

这通常不值得麻烦。请考虑根据已知的值集验证此类枚举。

如果您使枚举基于整数,您可以创建一个可用于检查有效性的伪值:

type Size int
const (
Small Size = iota
Medium
Large
maxSize // Always keep this at the end
)
var sizeToString = map[Size]string{
Small: "sm",
Medium: "md",
Large: "lg",
}
func (s Size) String() string {
return sizeToString[s]
}
func (s Size) Valid() bool {
return s > 0 && s < maxSize
}

如果将maxSize保留在const块的末尾,则Valid函数将始终有效,即使在添加或删除枚举值之后也是如此。

您可以对第二个枚举类型执行同样的操作,复合类型也可以定义Valid函数,如果两个枚举都有效,则返回true。

当我使用这个模式时,我总是包括一个单元测试,以确保每个枚举值都有一个字符串转换,这样我就不会忘记。您可以通过从0到maxSize进行for循环来完成此操作,并检查是否从未从sizeToString返回空字符串

最新更新