Enums 如何基于当前枚举值选择具有限制的随机枚举值? 上下文 对象朝一个方向移动:向上、向右、向下或向左 下一个方向将随机选择 下一个可能的方向不能是后退

Enums 如何基于当前枚举值选择具有限制的随机枚举值? 上下文 对象朝一个方向移动:向上、向右、向下或向左 下一个方向将随机选择 下一个可能的方向不能是后退,enums,rust,Enums,Rust,范例 如果它向右转,它可以向上,向右或向下,但不能向左 枚举 有一个简单的方向枚举: #[派生(调试,部分Q)] 枚举方向{ 向上的 正确的, 下来,, 左边 } 函数签名 我认为这是完成任务的函数签名: fn下一个方向(当前方向:方向)->方向 当前实施 这是我当前的实现: 使用兰德::前奏::*; fn下一个方向(当前方向:方向)->方向{ 设mut rng=thread_rng(); //可能的下一个方向 让next_dir_iter=[ 方向:向上, 方向:向下, 方向:左, 方向

范例

如果它向右转,它可以向上,向右或向下,但不能向左

枚举 有一个简单的方向枚举:

#[派生(调试,部分Q)]
枚举方向{
向上的
正确的,
下来,,
左边
}
函数签名 我认为这是完成任务的函数签名:

fn下一个方向(当前方向:方向)->方向
当前实施 这是我当前的实现:

使用兰德::前奏::*;
fn下一个方向(当前方向:方向)->方向{
设mut rng=thread_rng();
//可能的下一个方向
让next_dir_iter=[
方向:向上,
方向:向下,
方向:左,
方向:对,
]
.国际热核实验堆(iter)
.filter(|&dir |匹配(当前_dir,dir){
(方向::向上,方向::向下)=>false,
(方向::向下,方向::向上)=>错误,
(方向::左,方向::右)=>false,
(方向::右,方向::左)=>false,
(,)=>正确,
});
//选一个
让dir=next\u dir\u iter.选择(&mut rng).unwrap();
//返回方向,而不是返回方向(&D)
匹配目录{
方向::向上=>方向::向上,
方向::向下=>方向::向下,
方向::左=>方向::左,
方向::右=>方向::右,
}
}
这个函数能否以更清晰、更简单、更高效的方式编写

我想说的是可读性是一个优势,所以单行程序或代码高尔夫实现不可能是最佳的


我发现

您可以手工为每个案例写下可能的说明:

use rand::prelude::*;
use Direction::*;

#[derive(Debug, PartialEq, Copy, Clone)]
enum Direction {
    Up,
    Right,
    Down,
    Left,
}

impl Direction {
    fn next_random(self) -> Self {
        match self {
            Up => [Up, Left, Right],
            Down => [Down, Left, Right],
            Left => [Up, Down, Left],
            Right => [Up, Down, Right],
        }
        .choose(&mut thread_rng())
        .copied()
        .unwrap()
    }
}
当然,如果枚举有很多变体,最好有一个更通用的解决方案:

impl Direction {
    fn all() -> &'static [Self] {
        &[Up, Down, Left, Right]
    }

    fn opposite(self) -> Self {
        match self {
            Up => Down,
            Down => Up,
            Left => Right,
            Right => Left,
        }
    }

    fn next_random(self) -> Self {
        let next = Self::all()
            .iter()
            .filter(|&&d| d != self.opposite())
            .choose(&mut thread_rng());

        *next.unwrap()
    }
}
请注意,如果希望获得更好的性能或灵活性,可以将随机数生成器作为参数传递:

fn next_random(self, rng: &mut impl Rng) -> Self {
    let next = Self::all()
        .iter()
        .filter(|&&d| d != self.opposite())
        .choose(rng);

    *next.unwrap()
}

假设所有RNG都提供随机位,并且
choose()
方法将始终统一选择随机元素。传入RNG允许使用不同的RNG,例如,速度更快但不安全的RNG,或具有某种已知随机状态的RNG,以便您可以复制结果。它还允许在方法的多次调用中重用RNG,因此您无需每次调用
thread\u RNG()
。@SvenMarnach您将desserves注释为在单独的Q&AI中,知道我有点离题。:)我只是情不自禁地回复你关于不均匀分布的旁注。