作为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()
会导致错误,但似乎不是这种情况
这些方法在功能上是否相同?如果我匹配更复杂的物体,他们中的一个会崩溃吗?
答案 0 :(得分:6)
您无法移出不可变参考,因此您不必担心情况如此。
值得考虑的是,人们希望匹配工作有些类似于(Partial
)Eq
,并且需要&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,
}