Is it possible to match on the arm expression variants only in a submatch, as seen in the code comments below? I have a few instances of this pattern and would love to avoid having to add a _ => {} to the match statements even though I know it is useless.
Thanks in advance!
enum SomeOptions {
A,
B,
C,
D,
E,
F
}
fn main () {
let test = SomeOptions::A;
match test {
SomeOptions::A => {println!("A")},
SomeOptions::B | SomeOptions::C => {
// do complex things here that happen for either B or C
println!("B or C");
// I really want to match on the subset of options present
// in the match arm expression, but AFAIK I have to match
// on the outer variable again
match test {
SomeOptions::B => {println!("B")},
SomeOptions::C => {println!("C")},
// don't need to check for other options here,
// as the outer match is already doing that for us
// this is useless here
_ => {}
}
}
SomeOptions::D => {println!("D")},
// ignore other options for now.
_ => {}
}
}
What is the purpose of the inner match, precisely?
The presumed reason for using an | pattern is because that branch uses the same logic for both patterns. But the code you share doesn't do that; it combines flow control briefly and then splits again with a second match. In other words, the sample code is equivalent to:
if let SomeOptions::B | SomeOptions::C = &test {
println!("B or C");
}
match test {
SomeOptions::A => println!("A"),
SomeOptions::B => println!("B"),
SomeOptions::C => println!("C"),
SomeOptions::D => println!("D"),
_ => (),
}
The other option is using unreachable!() or unreachable_unchecked() in the catch-all arm on the inner match. The catch-all is required by the language. It's a feature that prevents logic errors.
The | pattern on the branch is used to have logic that runs when either of the 2 conditions happens, and then also run unique logic against both of the 2 conditions at the end of the block.
As a more concrete example, I have an application where I use the same form for editing and creating. The only difference is when displaying the name of the object, and when saving.
It seems like the compiler isn't smart enough to recognize that the match pattern is already restricted by the previous condition, and let me match on the sub-pattern defined by the outer match arm.
I'm not sure what that would even look like. You can get close, sort of, by switching the inner match to if-let-else-let.
match test {
SomeOptions::A => println!("A"),
SomeOptions::B | SomeOptions::C => {
println!("B or C");
if let SomeOptions::B = test {
println!("B");
} else if let SomeOptions::C = test {
println!("C");
}
}
SomeOptions::D => println!("D"),
_ => (),
}