选择随机枚举值的简单而安全的方法是什么?

What is a simple and safe way to choose a random enum value?

我需要从枚举中选择一个随机值。在一些关于 Nim 的文章中 我找到了这个解决方案:

import random

type Animal = enum
  Cat
  Dog
  Cow

echo rand(0..2).Animal

但这不能很好地扩展:如果向 枚举,我们必须调整上面的数字。

我们甚至会遇到运行时错误:

import random

type Animal = enum
  Cat
  Dog

randomize(123)

while true:
  echo rand(0..2).Animal
Cat
Cat
Dog
…/example.nim(10) example
…/.choosenim/toolchains/nim-1.4.4/lib/system/fatal.nim(49) sysFatal
Error: unhandled exception: value out of range: 2 notin 0 .. 1 [RangeDefect]

我正在寻找一种从枚举中选择随机值的简单方法1 那是安全的,意味着如果它编译,保证会有 没有 RangeDefect 或类似的运行时错误。

我也想知道是否有编译器设置 在上面的示例中至少生成一个警告。

编译器原则上似乎可以做到这一点:

Animal(5)

→ Error: 5 can't be converted to Animal

阅读 https://nim-lang.org/docs/random.html 后关于

我认为以下其中一项可以工作,但它们无法编译:

rand(Animal)

→ Error: type mismatch: got <type Animal>
rand(range(Animal))

→ Error: type mismatch: got <type Animal> but expected 'range = range (None)'
rand(range[Animal])

→ Error: expected range
rand(Slice[Animal])

→ Error: type mismatch: got <type Slice[example.Animal]>
rand(Slice(Animal))

→ Error: type mismatch: got <type Animal> but expected 'Slice = CompositeTypeClass'

这确实有效,但我想它的效率低得不必要,因为它需要 分配和填充序列:

import sequtils

echo sample(Animal.toSeq)

1我假设没有带漏洞的枚举,我知道这是 another issue.

一个简单的解决方案是使用 low and high:

rand(Animal.low..Animal.high)

使用通用过程允许编写 rand(Animal):

import random

type Animal = enum
  Cat
  Dog
  Cow

proc rand(T: typedesc): T =
  rand(T.low..T.high)

randomize(123)

for _ in 1..6:
  echo rand(Animal)

输出:

Cat
Cat
Dog
Cow
Cow
Dog