There is a type mismatch because you're trying to match an integer to a RangeInclusive object.
Here is a link to a working playground example. Unfortunately you are back to where you started and your original code is cleaner.
Frankly, I'm a little surprised that your first code worked! It looks like the compiler evaluates the pattern in the match statement to make the types work out. When you add the const I'm (totally) guessing it doesn't evaluate it any more.
Intrigued by this, I looked a little further and found this from the rust reference online. Now I'm confused again. Matching on ranges is specifically covered, so why doesn't a const pattern work? All you're saying is that the pattern will never change. It seems like it should work. Does anyone more knowledgeable than me know, should we file this as a compiler bug? @OptimisticPeach?
Edit: I searched the rustc issues and couldn't find anything obvious, but compilers are way above my skill level.
Sorry for the delay, I believe I know why it doesn't work.
When you use x..y in a pattern, it is just that, a pattern, so when you do the following:
match value {
x..y => {}
_ => {}
}
The compiler will explicitly match for values between x and y, meaning that it never actually constructs a RangeInclusive or Range, and instead actually matches for the range inline. Therefore, it doesn't work because you cannot match a type T to a type U.
Therefore you might be able to minimize your code to the following:
use std::ops::RangeInclusive;
const MY_RANGE_START: usize = 0;
const MY_RANGE_END: usize = 20;
const RANGE: RangeInclusive<usize> = MY_RANGE_START..=MY_RANGE_END;
fn main() {
let value = 10;
match value {
x if RANGE.contains(&x) => {}
_ => {}
}
}
But, of course this is still somewhat verbose, so I'd still use actual ranges.
Please note, I am not very knowledgeable about compiler internals, so please take this with a grain of salt.
I guess one of the problems here is the overloaded semantics of a..b and a..=b. You can use the syntax as a value constructor to create Range[Inclusive] objects, but when the same syntax is used as a pattern, it does not match or destructure Range[Inclusive] objects. Instead its meaning changes to checking whether an integer is in the given range.
Sure, but I think while it is a good goal that pattern matching should follow construction and vice versal (duals..) it isn't achievable in general. For example, the or-pattern A | B has no dual in expressions. We can only say they are duals for the specific case of bidirectional pattern synonyms (i.e. there's a bijection).
Indeed, | is not part of pattern syntax in general, but rather it is specifically part of match syntax.
(it was added to if let in 1.33.0, but it's still not considered to be part of pattern syntax proper)
Furthermore, because $(pat)|* is legal in match arms (i.e. | is in the follow-set of patterns), attempting to make it part of pattern syntax would be a pretty big breaking change. (this is in contrast to pat:ty, where such an extension was anticipated and : was not placed in the follow-set, enabling this RFC to exist)