是否应该在枚举之前取消引用枚举?

时间:2016-03-10 15:42:42

标签: pattern-matching rust dereference

作为Rust的新手,我偶然发现了一种在引用类型上运行match的两种显然有效的方法。

我已经定义了一个枚举:

enum Color {
    Red,
    Yellow,
    Green,
    Teal,
    Blue,
    Purple,
}

我想实现一个函数,该函数适用于此枚举实例的&self引用。

我可以看到两种编写这样一个函数的方法:

impl Color {
    // Approach #1: Match the reference, using references in each pattern
    fn contains_red(&self) -> bool {
        match self {
            &Color::Red => true,
            &Color::Yellow => true,
            &Color::Purple => true,
            _ => false,
        }
    }

    // Approach #2: Dereference &self and match the patterns directly
    fn contains_blue(&self) -> bool {
        match *self {
            Color::Blue => true,
            Color::Teal => true,
            Color::Purple => true,
            _ => false,
        }
    }
}

我预计解除引用&self会被视为一次移动,如果我连续两次在同一个实例上调用color.contains_blue()会导致错误,但似乎不是这种情况

这些方法在功能上是否相同?如果我匹配更复杂的物体,他们中的一个会崩溃吗?

3 个答案:

答案 0 :(得分:6)

您无法移出不可变参考,因此您不必担心情况如此。

值得考虑的是,人们希望匹配工作有些类似于(PartialEq,并且需要&self。换句话说,除非被迫,否则人们会期望隐含地引用它。通过一些实验很容易证实这一点。

值得注意的是*self 不是移动 - 它是对内存位置的引用。 It is thus an lvalue. Ergo,

  

当头部表达式为左值时,匹配不会分配临时位置(但是,按值绑定可以复制或移动左值)。

https://doc.rust-lang.org/reference.html#match-expressions

如果未分配临时位置,则无法进行移动。因此行为得到保证。作为括号内容,内部数据仍然可以从解构模式中移出,这会导致问题。但是,无论您是在self还是*self匹配,都是如此。

使用*self似乎是一种非正式的习惯用语,应该是首选。

答案 1 :(得分:1)

我个人更喜欢第二种。在我看来,它更好地传达了意图。

答案 2 :(得分:1)

从Rust 1.26开始,惯用的解决方案是都不是;您不必取消引用值&添加到模式:

fn contains_blue(&self) -> bool {
    match self {
        Color::Blue => true,
        Color::Teal => true,
        Color::Purple => true,
        _ => false,
    }
}

这要归功于改进的匹配人体工程学。

在这种情况下,您还可以使用模式交替:

match self {
    Color::Blue | Color::Teal | Color::Purple => true,
    _ => false,
}