rvi*_*dal 6 macros pattern-matching rust
从Rust 1.0开始,无法将多个模式分组到一个绑定中:
// It does not compile
match x as char {
b @ ('A' | 'Z') => println!("A or Z: {}", b),
_ => println!("Try again")
}
// Correct version
match x as char {
b @ 'A' | b @ 'Z' => println!("A or Z: {}", b),
_ => println!("Try again")
}
Run Code Online (Sandbox Code Playgroud)
我想知道宏是否可以完成绑定所有不同可能性的肮脏工作.以下是部分尝试:
macro_rules! bind_alternatives {
($x:ident, $e:expr) => ($x @ $e);
($x:ident, $e1:expr, $e2:expr) => (
$x @ $e1 | $x @ $e2
);
}
fn main() {
let x = 'a';
match x {
bind_alternatives!(z, 'a', 'c') => println!("Matched"),
_ => println!("No luck")
};
}
Run Code Online (Sandbox Code Playgroud)
这不编译:
example.rs:4:18: 4:19 error: macro expansion ignores token `|` and any following
example.rs:4 $x @ $e1 | $x @ $e2
^
example.rs:12:9: 12:40 note: caused by the macro expansion here; the usage of `bind_alternatives` is likely invalid in this context
example.rs:12 bind_alternatives!(z, 'a', 'c') => println!("Matched"),
Run Code Online (Sandbox Code Playgroud)
我知道宏可以扩展为模式,第一个支撑bind_alternatives确实有效.有可能推广到超过1种可能性吗?如果没有,是什么阻止了它?
宏可以扩展到模式、表达式和项目等内容,但不是所有内容;具体来说,宏扩展为完整的 AST 节点,但您在这里处理的不是完整的 AST 节点。
match表达式的每个分支都可以有一个或多个模式,由管道分隔,以及一个可选的模式保护 ( )。这是所有特殊的特定语法,因此不是完整的 AST 节点,因此不是宏可以扩展的内容。if conditionmatch
解析器正在其解析的那个点寻找模式,因此它将宏扩展为模式,该模式在 之前结束|,不适合模式语法。因此,宏产生的量超过了可以消耗的量,其余的会因错误而被丢弃。
我不确定这是什么时候改变的,但最初的帖子中的示例代码现在可以在 Rust 上编译1.63.0。
macro_rules! bind_alternatives {
($x:ident, $e:expr) => ($x @ $e);
($x:ident, $e1:expr, $e2:expr) => (
$x @ $e1 | $x @ $e2
);
}
fn main() {
let x = 'a';
match x {
bind_alternatives!(z, 'a', 'c') => println!("Matched"),
_ => println!("No luck")
};
foo(b'A')
}
fn foo(x: u8) {
// It DOES compile
match x as char {
b @ ('A' | 'Z') => println!("A or Z: {}", b),
_ => println!("Try again")
}
// Correct version
match x as char {
b @ 'A' | b @ 'Z' => println!("A or Z: {}", b),
_ => println!("Try again")
}
}
Run Code Online (Sandbox Code Playgroud)