是否应该在匹配之前取消对枚举的引用?

Should a reference to an enum be dereferenced before it is matched?

作为 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() 会导致错误,但这似乎不是案.

这些方法在功能上是否相同?如果我匹配更复杂的对象,其中一个会坏掉吗?

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

您无法移出不可变引用,因此您不必担心这种情况。

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

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

When the head expression is an lvalue, the match does not allocate a temporary location (however, a by-value binding may copy or move from the lvalue).

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

如果没有分配临时位置,则无法进行移动。因此,行为得到保证。正如附带说明的那样,内部数据仍然可以从解构模式中移出,这会导致问题。然而,无论您是在 self 还是 *self.

上进行匹配,这都是正确的

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

从 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,
}