let num = Some(5);
match num {
Some(x) if x < 5 => println!("{} < 5", x),
Some(x) if x > 5 => println!("{} > 5", x),
Some(5) => println!("5"),
None => println!("None"),
}
I get a compiler error because my patterns are non exhaustive:
non-exhaustive patterns: Some(i32::MIN..=4_i32) and Some(6_i32..=i32::MAX) not covered
I don't really understand what I'm missing, it seems to me that all cases are covered:
Some(x) with x < 5
Some(x) with x > 5
Some(x) with x = 5
None
But from what I understand from the error message, rust thinks I'm not covering cases 1 and 2.
The compiler does not attempt to understand if guards applying numeric range restrictions. It does understand range patterns (as long as they're ..= closed ranges rather than .. half-open ranges) and this code will be accepted without needing any catch-all condition:
It does not attempt to check how exhaustive conditional guards are at all because this is how the compiler is implemented. Even though your example might be easy to check, checking exhaustiveness is not an easy work in general.
Even if it checking the exhaustiveness of conditional guards were implemented, it could only be done for type the compiler knows implement Eq or Ord correctly. Consider this made-up example:
struct Silly(i32);
impl PartialEq for Silly
{
fn eq(&self, _: &Self) -> bool
{
false
}
fn ne(&self, _: &Self) -> bool
{
false
}
}
fn cmp(num: Option<Silly>)
{
match num
{
Some(x) if x == Silly(3) => println!("Equal!"),
Some(x) if x != Silly(3) => println!("Not Equal!"),
Some(_) => println!("Math fails!"),
None => println!("None")
}
}
fn main()
{
let num = Some(Silly(2));
cmp(num);
}
In this case the first two branches don't exhaust the range of values for Silly.
Correct, because they can be arbitrarily complicated. Rust is pretty consistent about this; you'll see that fn foo() -> i32 { if true { return 4 }; } also fails to compile.
If you want exhaustiveness, you have to phrase it as patterns, not conditionals.
For example, you could write
match letter {
Some('a') => println!("a"),
Some(_) => println!("not a"),
None => println!("None"),
}