如何从枚举中选择随机值? [英] How do I choose a random value from an enum?

查看:113
本文介绍了如何从枚举中选择随机值?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

纺锤的板条箱具有枚举,其中包含大量可能的微调框。

The spinners crate has an enum with a large selection of possible spinners.

以下是枚举(除了顶部和底部的4个值以外,所有值都被跳过):

Here's the enum (with all values except the top and bottom 4 skipped):

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();
}

但是,我希望随机选择一个微调器,但这不起作用:

However, I wish to select a spinner at random, and this does not work:

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

如何选择枚举

推荐答案

您自己的枚举



与Rust中的大多数抽象一样,随机值的生成受特征支持。对于任何特定类型,实现特征都是相同的,唯一的区别就是特征的方法和类型完全相同。

Your own enum

Like most abstractions in Rust, random value generation is powered by traits. Implementing a trait is the same for any particular type, the only difference is exactly what the methods and types of the trait are.

实施 Distribution 使用您的枚举作为类型参数。您还需要选择一种特定的分布类型。 Standard 是一个很好的默认选择。然后使用任何方法生成值,例如 rand :: random

use rand::{
    distributions::{Distribution, Standard},
    Rng,
}; // 0.7.0

#[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 0.4



实施 Rand 作为您的枚举,然后使用任何一种方法来生成值,例如 Rng :: gen

extern crate rand; // 0.4.2

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 板条箱可以消除对某些样板的需求,但对于Rand 0.5不存在。

Derive

The rand_derive crate can remove the need for some of this boilerplate, but does not exist for 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);
}



其他人的枚举



由于您无法控制枚举,因此必须将某物复制到您的代码中才能引用它。您可以创建一个枚举数组,并从中选择

Someone else's enum

Since you don't control the enum, you have to copy something into your code in order to reference it. You could create an array of the enum and choose from that:

use rand::seq::SliceRandom; // 0.7.0

mod another_crate {
    #[derive(Debug)]
    pub enum Spinner {
        One,
        Two,
        Three,
    }
}

fn main() {
    let mut rng = rand::thread_rng();
    let spinners = [
        another_crate::Spinner::One,
        another_crate::Spinner::Two,
        another_crate::Spinner::Three,
    ];
    let spinner = spinners.choose(&mut rng).unwrap();
    println!("{:?}", spinner);
}

您可以在本地复制整个枚举,实现 Rand ,然后有一种方法可以转换回其他板条箱表示形式。

You could replicate the entire enum locally, implement Rand for that, and then have a method that converts back into the other crates representation.

use rand::{
    distributions::{Distribution, Standard},
    Rng,
}; // 0.7.0

mod another_crate {
    #[derive(Debug)]
    pub enum Spinner {
        One,
        Two,
        Three,
    }
}

enum Spinner {
    One,
    Two,
    Three,
}

impl From<Spinner> for another_crate::Spinner {
    fn from(other: Spinner) -> another_crate::Spinner {
        match other {
            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 = another_crate::Spinner::from(rand::random::<Spinner>());
    println!("{:?}", spinner);
}

您可以计算微调框的数量并进行匹配:

You could count the number of spinners and do a match:

use rand::Rng; // 0.7.0

mod another_crate {
    #[derive(Debug)]
    pub enum Spinner {
        One,
        Two,
        Three,
    }
}

fn rando<R: Rng>(mut rng: R) -> another_crate::Spinner {
    match rng.gen_range(0, 3) {
        0 => another_crate::Spinner::One,
        1 => another_crate::Spinner::Two,
        _ => another_crate::Spinner::Three,
    }
}

fn main() {
    let mut rng = rand::thread_rng();
    let spinner = rando(&mut rng);
    println!("{:?}", spinner);
}

您可以实现 newtype 并实现随机

use rand::{distributions::Standard, prelude::*}; // 0.7.0

mod another_crate {
    #[derive(Debug)]
    pub enum Spinner {
        One,
        Two,
        Three,
    }
}

struct RandoSpinner(another_crate::Spinner);

impl Distribution<RandoSpinner> for Standard {
    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> RandoSpinner {
        RandoSpinner(match rng.gen_range(0, 3) {
            0 => another_crate::Spinner::One,
            1 => another_crate::Spinner::Two,
            _ => another_crate::Spinner::Three,
        })
    }
}

fn main() {
    let RandoSpinner(spinner) = rand::random();
    println!("{:?}", spinner);
}

另请参见:

  • How do I implement a trait I don't own for a type I don't own?

这篇关于如何从枚举中选择随机值?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆