Error E0008 seems overly restrictive. It prohibits using variables captured by value in a match arm in a guard expression (unless, it seems, the value implements Copy).
It does make sense that the guard expression shouldn’t be able to take ownership of the value, because then not only would you not be able to use the value in the body of the branch, but you wouldn’t be able to check any later branches either, since the value would already be consumed.
However, I don’t see why you can’t use a guard expression that only needs a reference.
Consider this:
enum Test {
A(i32),
B(String)
}
fn main() {
use Test::*;
let x = B("Hello!".into());
match x {
A(y) => println!("Got an int: {}", y),
B(s) if s.len() > 0 => println!("Got string with bytes: {:?}", s.into_bytes()),
B(_) => println!("Got an empty string")
}
}
In the second arm, we check the length of the string, but since s is captured by value, we get error E0008, even though the guard doesn’t actually need ownership. The description of the error gives the solution of capturing by ref, and if you need ownership, clone. However, this doesn’t always work. What if the body of the branch needs ownership of the original value and a clone doesn’t work, or is expensive.
There is a another workaround (not mentioned in the erro index):
match x {
A(y) => ...
B(s) => if s.len() > 0 {
...
} else {
...
}
And in this case, it isn’t too bad, but if the matching is more complicated, it can get kind of messy (ex requiring a nested match inside the else clause).
What’s even more suprising, is even this results in the error:
match x {
Some(s) if true => {}
None => {}
}
Even if the binding isn’t used in the guard expression at all it is an error. This is very surprising.
What I propose is that if a value is captured by value and doesn’t implement Copy (or whatever the rule is that triggers this error), then the variable should be bound by reference for the guard expression and ownership for the body.