如何放宽对已知变体的嵌套匹配的非详尽模式检查?
How do I relax the non-exhaustive patterns check for a nested match on known variants?
我如何说服 Rust 编译器内部 match
表达式在这里没问题,因为外部 match
已经限制了可能的类型?
enum Op {
LoadX,
LoadY,
Add,
}
fn test(o: Op) {
match o {
Op::LoadX | Op::LoadY => {
// do something common with them for code reuse:
print!("Loading ");
// do something specific to each case:
match o {
// now I know that `o` can only be LoadX | LoadY,
// but how to persuade the compiler?
Op::LoadX => print!("x"), /* LoadX specific */
Op::LoadY => print!("y"), /* LoadY specific */
_ => panic!("shouldn't happen!"),
}
println!("...");
}
Op::Add => println!("Adding"),
}
}
fn main() {
test(Op::LoadX);
test(Op::LoadY);
test(Op::Add);
}
我尝试了两种方法,但似乎都不起作用。
为 or 模式命名,然后使用该名称进行匹配:
match o {
load@(Op::LoadX | Op::LoadY) => {
// ...
match load {
// ...
}
}
这不是有效的 Rust 语法。
命名并绑定每个构造函数:
match o {
load@Op::LoadX | load@Op::LoadY => {
// ...
match load {
//...
}
}
仍然不满足详尽检查,因此出现相同的错误消息:
error[E0004]: non-exhaustive patterns: `Add` not covered
--> src/main.rs:14:19
|
14 | match load {
| ^ pattern `Add` not covered
有什么惯用的方法可以解决这个问题,还是我应该把 panic!("shouldn't happen")
放在各处或重构代码?
我认为你只需要重构你的代码,显然 LoadX
和 LoadY
非常接近。所以我认为你应该创建第二个枚举来重新组合它们:
enum Op {
Load(State),
Add,
}
enum State {
X,
Y,
}
fn test(o: Op) {
match o {
Op::Load(state) => {
// do something common with them for code reuse
print!("Loading ");
// do something specific to each case:
match state {
State::X => print!("x"),
State::Y => print!("y"),
}
println!("...");
}
Op::Add => println!("Adding"),
}
}
fn main() {
test(Op::Load(State::X));
test(Op::Load(State::Y));
test(Op::Add);
}
这对我来说更有意义。我认为这是表达你想要的更好的方式。
你不能。从概念上讲,没有什么能阻止你在外部匹配和内部匹配之间做 o = Op::Add
。变体完全有可能在两次比赛之间发生变化。
我可能会遵循 ,但如果您不想重构枚举,请记住 Rust 中有多种抽象技术。例如,functions 非常适合重用代码,closures(或特征)非常适合定制逻辑。
enum Op {
LoadX,
LoadY,
Add,
}
fn load<R>(f: impl FnOnce() -> R) {
print!("Loading ");
f();
println!("...");
}
fn test(o: Op) {
match o {
Op::LoadX => load(|| print!("x")),
Op::LoadY => load(|| print!("y")),
Op::Add => println!("Adding"),
}
}
fn main() {
test(Op::LoadX);
test(Op::LoadY);
test(Op::Add);
}
should I just put panic!("shouldn't happen")
您应该使用 unreachable!
而不是 panic!
,因为它在语义上对程序员来说更正确。
我如何说服 Rust 编译器内部 match
表达式在这里没问题,因为外部 match
已经限制了可能的类型?
enum Op {
LoadX,
LoadY,
Add,
}
fn test(o: Op) {
match o {
Op::LoadX | Op::LoadY => {
// do something common with them for code reuse:
print!("Loading ");
// do something specific to each case:
match o {
// now I know that `o` can only be LoadX | LoadY,
// but how to persuade the compiler?
Op::LoadX => print!("x"), /* LoadX specific */
Op::LoadY => print!("y"), /* LoadY specific */
_ => panic!("shouldn't happen!"),
}
println!("...");
}
Op::Add => println!("Adding"),
}
}
fn main() {
test(Op::LoadX);
test(Op::LoadY);
test(Op::Add);
}
我尝试了两种方法,但似乎都不起作用。
为 or 模式命名,然后使用该名称进行匹配:
match o { load@(Op::LoadX | Op::LoadY) => { // ... match load { // ... } }
这不是有效的 Rust 语法。
命名并绑定每个构造函数:
match o { load@Op::LoadX | load@Op::LoadY => { // ... match load { //... } }
仍然不满足详尽检查,因此出现相同的错误消息:
error[E0004]: non-exhaustive patterns: `Add` not covered --> src/main.rs:14:19 | 14 | match load { | ^ pattern `Add` not covered
有什么惯用的方法可以解决这个问题,还是我应该把 panic!("shouldn't happen")
放在各处或重构代码?
我认为你只需要重构你的代码,显然 LoadX
和 LoadY
非常接近。所以我认为你应该创建第二个枚举来重新组合它们:
enum Op {
Load(State),
Add,
}
enum State {
X,
Y,
}
fn test(o: Op) {
match o {
Op::Load(state) => {
// do something common with them for code reuse
print!("Loading ");
// do something specific to each case:
match state {
State::X => print!("x"),
State::Y => print!("y"),
}
println!("...");
}
Op::Add => println!("Adding"),
}
}
fn main() {
test(Op::Load(State::X));
test(Op::Load(State::Y));
test(Op::Add);
}
这对我来说更有意义。我认为这是表达你想要的更好的方式。
你不能。从概念上讲,没有什么能阻止你在外部匹配和内部匹配之间做 o = Op::Add
。变体完全有可能在两次比赛之间发生变化。
我可能会遵循
enum Op {
LoadX,
LoadY,
Add,
}
fn load<R>(f: impl FnOnce() -> R) {
print!("Loading ");
f();
println!("...");
}
fn test(o: Op) {
match o {
Op::LoadX => load(|| print!("x")),
Op::LoadY => load(|| print!("y")),
Op::Add => println!("Adding"),
}
}
fn main() {
test(Op::LoadX);
test(Op::LoadY);
test(Op::Add);
}
should I just put
panic!("shouldn't happen")
您应该使用 unreachable!
而不是 panic!
,因为它在语义上对程序员来说更正确。