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

mkr*_*er1 5 random enums nim-lang

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

import random

type Animal = enum
  Cat
  Dog
  Cow

echo rand(0..2).Animal
Run Code Online (Sandbox Code Playgroud)

但这不能很好地扩展:如果在枚举中添加或删除了一些值,我们必须调整上限值。

我们甚至可以得到一个运行时错误:

import random

type Animal = enum
  Cat
  Dog

randomize(123)

while true:
  echo rand(0..2).Animal
Run Code Online (Sandbox Code Playgroud)
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]
Run Code Online (Sandbox Code Playgroud)

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

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

编译器原则上似乎能够做到这一点:

Animal(5)

? Error: 5 can't be converted to Animal
Run Code Online (Sandbox Code Playgroud)

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

我认为以下方法之一可以工作,但它们无法编译:

rand(Animal)

? Error: type mismatch: got <type Animal>
Run Code Online (Sandbox Code Playgroud)
rand(range(Animal))

? Error: type mismatch: got <type Animal> but expected 'range = range (None)'
Run Code Online (Sandbox Code Playgroud)
rand(range[Animal])

? Error: expected range
Run Code Online (Sandbox Code Playgroud)
rand(Slice[Animal])

? Error: type mismatch: got <type Slice[example.Animal]>
Run Code Online (Sandbox Code Playgroud)
rand(Slice(Animal))

? Error: type mismatch: got <type Animal> but expected 'Slice = CompositeTypeClass'
Run Code Online (Sandbox Code Playgroud)

这确实有效,但我猜它不必要地低效,因为它需要分配和填充一个序列:

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]
Run Code Online (Sandbox Code Playgroud)

1我假设没有带孔的枚举,我知道这是 另一个问题

mkr*_*er1 9

一个简单的解决方案是使用lowand high

rand(Animal.low..Animal.high)
Run Code Online (Sandbox Code Playgroud)

使用通用 proc 允许编写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)
Run Code Online (Sandbox Code Playgroud)

输出:

Cat
Cat
Dog
Cow
Cow
Dog
Run Code Online (Sandbox Code Playgroud)