spinners包装箱中有一个enum,其中包含大量可能的纺纱工具。
这是枚举(除跳过顶部和底部4之外的所有值):
pub enum Spinners {
Dots,
Dots2,
Dots3,
Dots4,
...
Shark,
Dqpb,
Weather,
Christmas,
}
新的微调器很容易创建:
extern crate spinners;
use spinners::{Spinner, Spinners};
use std::thread::sleep;
use std::time::Duration;
fn main() {
let sp = Spinner::new(Spinners::Dots9, "Waiting for 3 seconds".into());
sleep(Duration::from_secs(3));
sp.stop();
}
但是,我希望随机选择一个微调器,这不起作用:
let spinner_enum = rng.choose(Spinners).unwrap_or(&Spinners::Dots9);
由于:
error[E0423]: expected value, found enum `Spinners`
let spinner_enum = rng.choose(Spinners).unwrap_or(&Spinners::Dots9);
^^^^^^^^ not a value
如何随机选择枚举值,并使用它来显示随机微调器?
答案 0 :(得分:15)
与Rust中的大多数抽象一样,随机值生成由特征提供支持。对于任何特定类型,实现特征都是相同的,唯一的区别在于特征的方法和类型。
使用您的枚举作为类型参数实施Distribution
。您还需要选择特定类型的分发; Standard
是一个很好的默认选择。然后使用任何方法生成值,例如rand::random
:
extern crate rand;
use rand::{
distributions::{Distribution, Standard},
Rng,
};
#[derive(Debug)]
enum Spinner {
One,
Two,
Three,
}
impl Distribution<Spinner> for Standard {
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Spinner {
match rng.gen_range(0, 3) {
0 => Spinner::One,
1 => Spinner::Two,
_ => Spinner::Three,
}
}
}
fn main() {
let spinner: Spinner = rand::random();
println!("{:?}", spinner);
}
为您的枚举实施Rand
,然后使用任何方法生成值,例如Rng::gen
:
extern crate rand;
use rand::{Rand, Rng};
#[derive(Debug)]
enum Spinner {
One,
Two,
Three,
}
impl Rand for Spinner {
fn rand<R: Rng>(rng: &mut R) -> Self {
match rng.gen_range(0, 3) {
0 => Spinner::One,
1 => Spinner::Two,
_ => Spinner::Three,
}
}
}
fn main() {
let mut rng = rand::thread_rng();
let spinner: Spinner = rng.gen();
println!("{:?}", spinner);
}
rand_derive
crate可以消除对某些样板的需求,但对于Rand 0.5不存在。
extern crate rand;
#[macro_use]
extern crate rand_derive;
use rand::Rng;
#[derive(Debug, Rand)]
enum Spinner {
One,
Two,
Three,
}
fn main() {
let mut rng = rand::thread_rng();
let spinner: Spinner = rng.gen();
println!("{:?}", spinner);
}
由于您无法控制枚举,因此您必须将某些内容复制到您的代码中才能引用它。您可以从中创建一个枚举数组choose
:
extern crate rand;
#[derive(Debug)]
enum Spinner {
One,
Two,
Three,
}
use rand::Rng;
fn main() {
let mut rng = rand::thread_rng();
let spinners = [Spinner::One, Spinner::Two, Spinner::Three];
let spinner = rng.choose(&spinners).unwrap();
println!("{:?}", spinner);
}
您可以在本地复制整个枚举,为此实现Rand
,然后有一个转换回其他包装箱表示的方法。
extern crate rand;
use rand::{
distributions::{Distribution, Standard},
Rng,
};
mod another_crate {
#[derive(Debug)]
pub enum Spinner {
One,
Two,
Three,
}
}
enum Spinner {
One,
Two,
Three,
}
impl Spinner {
fn to_other(&self) -> another_crate::Spinner {
match *self {
Spinner::One => another_crate::Spinner::One,
Spinner::Two => another_crate::Spinner::Two,
Spinner::Three => another_crate::Spinner::Three,
}
}
}
impl Distribution<Spinner> for Standard {
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Spinner {
match rng.gen_range(0, 3) {
0 => Spinner::One,
1 => Spinner::Two,
_ => Spinner::Three,
}
}
}
fn main() {
let spinner = rand::random::<Spinner>().to_other();
println!("{:?}", spinner);
}
您可以计算微调器的数量并进行匹配:
extern crate rand;
use rand::Rng;
#[derive(Debug)]
enum Spinner {
One,
Two,
Three,
}
fn rando<R: Rng>(mut rng: R) -> Spinner {
match rng.gen_range(0, 3) {
0 => Spinner::One,
1 => Spinner::Two,
_ => Spinner::Three,
}
}
fn main() {
let mut rng = rand::thread_rng();
let spinner = rando(&mut rng);
println!("{:?}", spinner);
}
您可以实现 newtype 并为其实现随机生成:
extern crate rand;
use rand::{distributions::Standard, prelude::*};
#[derive(Debug)]
enum Spinner {
One,
Two,
Three,
}
struct RandoSpinner(Spinner);
impl Distribution<RandoSpinner> for Standard {
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> RandoSpinner {
RandoSpinner(match rng.gen_range(0, 3) {
0 => Spinner::One,
1 => Spinner::Two,
_ => Spinner::Three,
})
}
}
fn main() {
let RandoSpinner(spinner) = rand::random();
println!("{:?}", spinner);
}
另见:
答案 1 :(得分:2)
自Shepmaster asked以来,我可以提出另外两种选择。
不幸的是rng.choose(Spinners)
无法工作,因为没有办法迭代枚举值;见:In Rust, is there a way to iterate through the values of an enum?
您可以使用strum EnumIter
来允许迭代。在Rand 0.4和0.5中,choose
不支持迭代器,但您可以将所有选项收集到Vec
中,也可以枚举并匹配索引。在Rand 0.6中,将有一个choose
支持迭代器的变体,虽然它可能会很慢(取决于我们是否可以为ExactSizeIterator
s优化它。)
use rand::prelude::*;
#[derive(EnumIter)]
enum Spinner { ... }
let mut rng = thread_rng();
let options = Spinner::iter().collect::<Vec<_>>();
let choice = rng.choose(&options);
// or:
let index = rng.gen_range(0, MAX);
let choice = Spinner::iter().enumerate().filter(|(i, _)| i == index).map(|(_, x)| x).next().unwrap();
// with Rand 0.6, though this may be slow:
let choice = Spinner::iter().choose(&mut rng);
// collecting may be faster; in Rand 0.6 this becomes:
let choice = Spinner::iter().collect::<Vec<_>>().choose(&mut rng);
另一种选择是将FromPrimitive
trait num-derive与{{3}}一起使用:
#[derive(FromPrimitive)]
enum Spinner { ... }
let choice = Spinner::from_u32(rng.gen_range(0, MAX)).unwrap();