As a newcomer to Rust, I've stumbled upon two apparently valid ways of running a match
on a reference type.
I've defined an enum:
enum Color {
Red,
Yellow,
Green,
Teal,
Blue,
Purple,
}
I want to implement a function that works on a &self
reference of an instance of this enum.
I can see two ways to write such a function:
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,
}
}
}
I expected that dereferencing &self
would be counted as a move, and would cause errors if I called color.contains_blue()
on the same instance twice in a row, but this doesn't seem to be the case.
Are these approaches functionally identical? Would one of them break down if I were matching more complex objects?
I personally prefer the second. It conveys the intent better, in my opinion.
You can't move out of an immutable reference, so you don't have to worry about that being the case.
It's worth considering that one would expect matches to work somewhat akin to (
Partial
)Eq
, and that takes&self
. In other words, one would expect it to take a reference implicitly unless forced. This is easily confirmed with a little experimentation.It's worth noting that
*self
is not a move - it's a reference to a memory location. It is thus an lvalue. Ergo,https://doc.rust-lang.org/reference.html#match-expressions
If a temporary location is not allocated, a move cannot occur. Thus the behaviour is guaranteed. As the parenthetical notes, internal data can still get moved out from destructuring pattern, which would cause a problem. This, however, is true regardless of whether you are matching on
self
or*self
.Using
*self
seems to be an informal idiom, and should be preferred.As of Rust 1.26, the idiomatic solution is neither; you don't have to dereference the value or add
&
to the patterns:This is thanks to improved match ergonomics.
You can also use pattern alternation in this case: