Could somebody please explain to me, why DOG and BIRD are marked by Rust as unreachable patterns?
fn main() {
let CAT:&str ="CAT";
let DOG:&str ="DOG";
let BIRD:&str ="BIRD";
let value = "CAT";
match value
{
CAT=>ANIMAL::CAT,
DOG=>ANIMAL::DOG,
BIRD=>ANIMAL::BIRD,
_=>panic!("Not a recognized animal")
};
}
enum ANIMAL
{
CAT,
DOG,
BIRD,
}
A path pattern has to be an enum variant, const or associated const, or some type. Instead you've named some variables, which instead acts like an identifier. That is, you're unconditionally binding the value to new variables named CAT, DOG, and BIRD as if you did
let CAT = value;
(A match isn't just short for some runtime if-else like checks, which is why the compiler can check for exhaustiveness at compile time.)
Consider this example. When I pass in 123, it doesn't match the first three patterns. In the fourth pattern, the value is bound to a new variable x, which I then use in the print. That last pattern can't fail to match.
Your OP does something similar (the first pattern binds the value to a new variable CAT and can't fail to match -- which is why the other patterns are unreachable).
Because match doesn't compare variables, it destructures and compares values (literals or consts). The values in variables can vary at run time (i.e. aren't known at compile time), generally speaking; literals and consts cannot.
If you want to compare variables, use if-else.
if value == CAT {
Animal::CAT
} else if value == DOG {
Animal::DOG
} else if value == BIRD {
Animal::BIRD
};
Or maybe
match value {
_ if value == CAT => Animal::CAT,
_ if value == DOG => Animal::DOG,
_ if value == BIRD => Animal::BIRD,
_ => panic!("..."),
}
But since the values you want to compare are all known at compile time, const (or literals) is the better option.
This stems from an ambiguous pattern syntax, which is an unfortunate gotcha.
Consider this code:
match 123 {
a => { println!("a"); }
b => { println!("b"); }
}
What does this mean?
Turns out it can mean two different things:
Set the variable a to the value 123 and print "a". playground
Compare the value 123 with the constant value a, and print "a" if it is equal, "b" if it is unequal. playground
The way the ambiguity is resolved is by whether a is a constant. If there is no such constant, interpretation 1 is used. If there is such a constant, interpretation 2 is used.
In your code, there is technically no constant CAT, even though you have an immutable variable CAT. The way it works is variables created by let don't count as compile-time constants. Therefore, interpretation 1 is used and match creates a new variable CAT that shadows the original variable CAT.
Thank you very much for your explanation. Now I understand. Tbh, I'm not sure why scenario 1 described by you was ever considered to make sense, but hey, I don't make the rules. I just live by them
Once again, thank you for your explanation, it really helped me to understand.