【问题标题】:Is there a better way to write this code for the inverse of a direction in rust?有没有更好的方法来为 Rust 的反方向编写这段代码?
【发布时间】:2022-12-08 05:56:35
【问题描述】:

我试图从这个枚举中获得与 MovableDirection 相反的方向:

enum MovableDirection {
    None,
    Up,
    Down,
    Right,
    Left,
}

所以MovableDirection::Up的反义词是MovableDirection::DownMovableDirection::LeftMovableDirection::Right,等等。

我为它写了这个函数:

fn inverse_dir(dir: MovableDirection) -> MovableDirection {
    match dir {
        MovableDirection::Up  => return MovableDirection::Down,
        MovableDirection::Down => return MovableDirection::Up,
        MovableDirection::Left => return MovableDirection::Right,
        MovableDirection::Right => return MovableDirection::Left,
        MovableDirection::None => return MovableDirection::None,
    }
}

我对它的功能很满意,但我情不自禁地觉得有更好、更简洁的方法可以做到这一点。感谢您提供任何帮助,如果没有也没关系,非常感谢。

【问题讨论】:

  • 您可以省略 inverse_dir 内的 returns 和 use MovableDirection::*

标签: rust enums


【解决方案1】:

您的代码比需要的更冗长,Clippy 会指出:

warning: unneeded `return` statement
  --> src/lib.rs:11:34
   |
11 |         MovableDirection::Up  => return MovableDirection::Down,
   |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   |
   = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_return
   = note: `#[warn(clippy::needless_return)]` on by default
   = help: remove `return`

在 Rust 中一切都是表达式,返回函数体中的最后一个表达式。您只需要 return 关键字即可提前返回。所以你可以按照 Clippy 的建议重写如下:

fn inverse_dir(dir: MovableDirection) -> MovableDirection {
    use MovableDirection::*;
    match dir {
        Up => Down,
        Down => Up,
        Left => Right,
        Right => Left,
        None => None,
    }
}

真的没有比这更短的写法了。 enum 并没有本质上对这些关系进行编码。你必须不知何故写下从每个变体到其对立面的映射,每个映射可能需要一行。


作为更一般的评论,您可以考虑删除 None 变体并改用 Option<MovableDirection>。与您所拥有的相比,这将没有运行时开销,并且可以让您在不需要的地方忽略 None 变体。您还将免费获得Option 的所有方法和特征实现。

【讨论】:

    【解决方案2】:

    没有真正“更干净”的方法来做到这一点,但有几点提出质疑,一个是风格,不需要使用 return,另一个是 None 在这里看起来不对,你最好使用 Option 代替, 最后你可以实现 Not trait:

    use core::ops::Not;
    
    #[derive(PartialEq, Eq, Debug)]
    enum MovableDirection {
        Up,
        Down,
        Right,
        Left,
    }
    
    impl Not for MovableDirection {
        type Output = Self;
    
        fn not(self) -> Self::Output {
            match self {
                Self::Up => Self::Down,
                Self::Down => Self::Up,
                Self::Left => Self::Right,
                Self::Right => Self::Left,
            }
        }
    }
    
    fn main() {
        let up = MovableDirection::Up;
        let down = !up;
        
        let opt = Some(down);
        
        assert_eq!(Some(MovableDirection::Down), opt);
    }
    

    如果你想保留 None,Neg 可能更适合:

    use core::ops::Neg;
    
    #[derive(PartialEq, Eq, Debug)]
    enum MovableDirection {
        None,
        Up,
        Down,
        Right,
        Left,
    }
    
    impl Neg for MovableDirection {
        type Output = Self;
    
        fn neg(self) -> Self::Output {
            match self {
                Self::None => Self::None,
                Self::Up => Self::Down,
                Self::Down => Self::Up,
                Self::Left => Self::Right,
                Self::Right => Self::Left,
            }
        }
    }
    
    fn main() {
        assert_eq!(MovableDirection::Down, -MovableDirection::Up);
        assert_eq!(MovableDirection::None, -MovableDirection::None);
    }
    

    【讨论】:

    • Neg 代替 Not 怎么样?
    • @KevinReid 添加,谢谢
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-03-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多