This question also hurdles me sometimes. I think the mental model should first be this:
the scrutinee, i.e. the expression that is matched on in match expressions, and the match arms should be the same type!
So, for match *list
, the type of scrutinee *list
is List, so the type of arms (i.e. Cons
and Nil
) is List
.
If you write Cons(var)
, i.e. bind the value to a variable, then the ownership is moved. But since List
is not Copy, you can't do it from &List
, and you'll get the error with solutions: Rust Playground
error[E0507]: cannot move out of `list` as enum variant `Cons` which is behind a shared reference
--> src/main.rs:15:11
|
15 | match *list {
| ^^^^^
16 | Cons(x) => x.len() as _,
| -
| |
| data moved here
| move occurs because `x` has type `String`, which does not implement the `Copy` trait
|
help: consider removing the dereference here
|
15 - match *list {
15 + match list {
|
But, some ergonomics happen here, like:
Cons(_)
contains the wildcard pattern, which doesn't consume the ownership. So your code now passes.
Unlike identifier patterns, wildcard pattern _
does not copy, move or borrow the value it matches.
src: Patterns - The Rust Reference
Update: the binding modes in the Reference book are officially ducomented as follows
When a reference value is matched by a non-reference pattern, it will be automatically treated as a ref
or ref mut
binding.
Non-reference patterns include all patterns except bindings, wildcard patterns (_
), const
patterns of reference types, and reference patterns.
If a binding pattern does not explicitly have ref
, ref mut
, or mut
, then it uses the default binding mode to determine how the variable is bound. The default binding mode starts in "move" mode which uses move semantics. When matching a pattern, the compiler starts from the outside of the pattern and works inwards. Each time a reference is matched using a non-reference pattern, it will automatically dereference the value and update the default binding mode. References will set the default binding mode to ref
. Mutable references will set the mode to ref mut
unless the mode is already ref
in which case it remains ref
. If the automatically dereferenced value is still a reference, it is dereferenced and this process repeats.
Move bindings and reference bindings can be mixed together in the same pattern. Doing so will result in partial move of the object bound to and the object cannot be used afterwards. This applies only if the type cannot be copied.
src: Patterns - The Rust Reference