#random #enums #nim-lang
#Случайный #перечисления #ним-ланг
Вопрос:
Мне нужно было выбрать случайное значение из перечисления. В какой-то статье о 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, Rand,HSlice[T: Порядковый номер или float или float32 или float64,T: порядковый номер или float или float32 или float64]
- rand, HSlice[T: Порядковый номер или float или float32 или float64,T: порядковый номер или float или float32 или float64]
- rand,типdesc[T]
Я думал, что одно из следующих действий может сработать, но они не компилируются:
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 Я предполагаю, что нет перечислений с отверстиями, которые, как я знаю, являются
еще одной проблемой.
Ответ №1:
Простым решением является использование low
и 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
Комментарии:
1. просто хотел добавить, что это не будет компилироваться для перечисления с дырами, что решает вашу проблему безопасности. здесь вы используете rand(HSlice[Animal])