-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Description
The current if let $pattern = $expr {}
functionality is great when you're de-structuring parts of the pattern for use in the if-scope. However, when matching without that need it can feel quite limited. I would suggest allowing macroless evaluation of certain pattern matches -> bool
.
Current State
Example compile error:
enum Example {
A(i32, &'static str),
B(i32, bool),
}
let example = Example::A(123, "alex");
let always_do_it = true;
if let Example::A(.., "alex") = example || always_do_it {
// compile error!
}
This makes sense when you can reference part of the pattern within the if-scope, but less so when it's a straight forward match.
The macroless way of mapping a pattern match to a boolean can currently be a little ugly.
if if let Example::A(.., "alex") = example { true } else { false} || always_do_it {
// works, but ugly enough to have to split out
}
let examples: IntoIter<Example> = ...
// filter away the A-123 cases, difficult to read
examples.filter(|t| if let Example::A(123, ..) = *t { false } else { true });
New functionality
How about we allow pattern matches without a variable binding to be evaluated as bools.
let is_a_123: bool = let Example::A(123, ..) = example;
This would mean the above examples would start working / could be more readable.
if let Example::A(.., "alex") = example || always_do_it {
// works now
}
examples.filter(|t| !let Example::A(123, ..) = *t) // nicer
Its worth noting explicitly that I would expect patterns with variable bindings to not be allowed
// compile error! variable bindings are not allowed in pattern -> bool evaluations
let is_a_123: bool = let Example::A(123, some_str) = example;
This means this functionality would have a clear distinction from the current if let $pattern = $expr {}
usage.
Working example
I'd like this as macroless functionality built into the language. However, I can provide a simple macro for a working example.
macro_rules! iff {
(let $p:pat = $e:expr) => {{
if let $p = $e { true } else { false }
}};
}
let is_a_123: bool = iff!(let Example::A(123, ..) = example);
if iff!(let Example::A(.., "alex") = example) || always_do_it {}
examples.filter(|t| !iff!(let Example::A(123, ..) = *t));
These are not nice, but show the functionality working as close as we can currently get.
Comments
I think this would make a good addition to the current if let
behaviour. So please fill me in on all the obvious stuff I've missed!