在进行枚举匹配之前,应将枚举引用取消引用吗?

6
作为Rust的新手,我遇到了两种似乎都可以的用于引用类型匹配的方法。
我定义了一个枚举:
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(),就会导致错误,但事实并非如此。

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


2
我被告知要取消匹配参数(您的第二种方法),因为它更符合惯用法,因为它具有较少的杂乱无章。希望有人能发表更权威的答案。 :-) - Shepmaster
只是为了确认一下:Color 不是 Copy,对吧? - Matthieu M.
@Matthieu 不,它是如上所示定义的,没有任何属性。但如果这对行为有重大影响,我很乐意听取意见。 - KChaloux
是的,我也非常确定第二种方法是惯用的,但我也无法提供任何支持这一说法的链接 :) 而且,我相信匹配的值是“Copy”还是其他并没有什么区别。 - Vladimir Matveev
@Shepmaster 风格指南够权威吗?https://doc.rust-lang.org/style/features/match.html(好吧,不完全一样,但还是...) - starblue
@starblue 我认为那将是一个很好的答案。这至少是来自 Rust 的创造者的观点,他们应该知道如何使用他们的语言。然而,我仍然想知道两种方法之间是否存在真正的功能差异,或者它只是一种风格问题。 - KChaloux
3个回答

8

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

值得考虑的是,人们期望匹配类似于(Partial)Eq工作,这需要使用&self。换句话说,人们期望它会隐式地取一个引用,除非强制执行。通过一些实验,可以轻松确认这一点。

值得注意的是,*self不是移动(move)——它是对内存位置的引用。 因此,它是左值(lvalue)。因此,

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

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

如果未分配临时位置,则不能进行移动。因此,行为是有保证的。如同括号内所述,从解构模式中仍然可以移出内部数据,这可能会导致问题。但是,无论您是否在匹配self还是*self,这都是真实的。

使用*self似乎是一种非正式的习惯用法,并且应该被优先选择。


1
这有助于很好地澄清事情。知道在使用某个东西作为lvalue时不能发生移动是很有道理的。 - KChaloux

3

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

1

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接