当前位置: 首页 > 知识库问答 >
问题:

如何从枚举中选择随机值?

宗政财
2023-03-14

微调器板条箱有一个枚举,其中包含大量可能的微调器。

这是枚举(跳过除顶部和底部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

如何随机选择枚举值,并使用该值显示随机微调器?

共有3个答案

仉宸
2023-03-14

在将来的这里,我们可能会使用strum\u宏::FromRepr和EnumCount:https://docs.rs/strum_macros/0.24.0/strum_macros/derive.FromRepr.html

use strum::EnumCount;
use strum_macros::{EnumCount, FromRepr};

#[derive(FromRepr, Debug, PartialEq, EnumCount)]
enum Spinners{ Dots, Dots2, ... }

let randomInteger = 0;  //Worst RNG ever!
assert_eq!(Some(Spinners::Dots), Spinners::from_repr(randomInteger));


let spinner_enum =
    Spinners::from_repr(rng.gen_range(0..Spinners::COUNT))
    .unwrap_or(&Spinners::Dots9);

计数由EnumCount自动创建和分配。from\U repr在数字与变量不对应时返回None,例如可能太高,或者您为一个或多个变量指定了数字,从而留下了间隙。

编辑:微调器板条箱可能无法与FromRepr一起使用,因为它需要注释枚举的定义,而据我所知,除非修改代码,否则无法使用;如果您这样做了,请发布拉取请求!但如果您已经定义了自己的枚举,那么Bob就是您的叔叔。

梅安平
2023-03-14

既然Shepmaster问了我,我可以建议另外两个选择。

不幸的是。选择(微调器)无法工作,因为无法迭代枚举值;请参阅:在Rust中,是否有方法遍历枚举的值?

您大概可以使用strum的EnumIter来允许迭代。在Rand 0.4和0.5中,select不支持迭代器,但您可以将所有选项收集到Vec中,或者枚举并匹配索引。在Rand 0.6中,将有一个支持迭代器的select变体,尽管它可能会很慢(取决于我们是否可以针对ExactSizeIterators对其进行优化)。

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

另一种选择是将num的FromPrimitivetrait与num-派生一起使用:

#[derive(FromPrimitive)]
enum Spinner { ... }

let choice = Spinner::from_u32(rng.gen_range(0, MAX)).unwrap();
籍弘伟
2023-03-14

与Rust中的大多数抽象一样,随机值生成由特征提供支持。实现任何特定类型的特征都是一样的,唯一的区别是特征的方法和类型。

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

use rand::{
    distributions::{Distribution, Standard},
    Rng,
}; // 0.8.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) { // rand 0.5, 0.6, 0.7
        match rng.gen_range(0..=2) { // rand 0.8
            0 => Spinner::One,
            1 => Spinner::Two,
            _ => Spinner::Three,
        }
    }
}

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

为枚举实现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\U派生板条箱可以消除对某些样板的需要,但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);
}

由于您不控制枚举,因此您必须将某些内容复制到代码中才能引用它。您可以创建枚举数组并从中选择

use rand::seq::SliceRandom; // 0.8.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,然后使用一个方法将其转换回其他crates表示。

use rand::{
    distributions::{Distribution, Standard},
    Rng,
}; // 0.8.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..=2) {
            0 => Spinner::One,
            1 => Spinner::Two,
            _ => Spinner::Three,
        }
    }
}

fn main() {
    let spinner = another_crate::Spinner::from(rand::random::<Spinner>());
    println!("{:?}", spinner);
}

您可以计算纺纱机的数量并进行匹配:

use rand::Rng; // 0.8.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..=2) {
        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);
}

您可以实现一个新类型并实现该类型的随机生成:

use rand::{distributions::Standard, prelude::*}; // 0.8.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..=2) {
            0 => another_crate::Spinner::One,
            1 => another_crate::Spinner::Two,
            _ => another_crate::Spinner::Three,
        })
    }
}

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

另见:

  • 我如何为我不拥有的类型实现我不拥有的特性
 类似资料:
  • 我需要java JAVA CODE中此解决方案的delphi解决方案

  • 我的问题很简单。我有以下几点: 如何从该枚举中选择随机元素?我试着解决这个问题,但没有成功。

  • 问题内容: 如果我有这样的枚举: 随机挑选一个的最佳方法是什么?它不需要是生产质量的防弹产品,但是相当均匀的分配将是不错的选择。 我可以做这样的事情 但是有更好的方法吗?我觉得这是之前已解决的问题。 问题答案: 我唯一建议的是缓存结果,因为每个调用都会复制一个数组。另外,不要每次都创建一个。保持一个。除此之外,您在做什么都很好。所以:

  • 如果我有这样的枚举: 随机挑选的最佳方式是什么?它不需要是生产质量的防弹产品,但一个相当均匀的分布将是很好的。 我可以做这样的事 但是有没有更好的方法呢?我觉得这是以前解决过的问题。

  • 我正在编写一个二十一点游戏。我有一个所有可用牌类型的枚举。交易时,我想使用Random从枚举中随机选择一张牌给玩家。如何使用整数值对应枚举值?或者,我如何为该枚举的变量随机选择枚举值? 纸牌Enun:

  • 我正在尝试从以下枚举中筛选,以根据随机机会选择其中一个值。 目前,我正在使用此代码选择一个值。 还有我的随机效用函数 目前,大多数情况下,它将准确地选择一个没有问题的层值。然而,大约在的时候,我会得到一个索引arrayoutofbounds。 我知道这是因为枚举中的机会分散到很远的地方(因为如果我向枚举添加更多值,机会不会像它们那样分散,那么就不会发生此异常)。 如何修复此错误?或者有更好的方法