我正在深入研究 Rust 宏,我想尝试一些东西,但我就是无法让它工作
macro_rules! expr_enum {
(base($ch:expr)) => {
{
let expression = Enum::Base($ch);
expression
}
};
(not($inner:tt)) => {
{
let inner_expr = expr_enum!($inner);
let pointer_inner = Box::new(inner_expr);
Enum::Not(pointer_inner)
}
};
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum Enum {
Base(char),
Not(Box<Enum>),
And(Vec<Enum>),
Or(Vec<Enum>),
}
fn main() {
let expr1:Enum = expr!(base('A'));
let expr2:Enum = expr!(not(base('A')));
println!("{:?}",expr1);
println!("{:?}",expr2);
println!("{:?}",expr3);
println!("{:?}",expr4);
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum Enum {
Base(char),
Not(Box<Enum>),}
fn main() {
let expr1:Enum = expr!(base('A'));
let expr2:Enum = expr!(not(base('A')));
println!("{:?}",expr1);
println!("{:?}",expr2);
}
我尝试观看一些视频,阅读编译器错误,观看大学演示,到处阅读一些在线信息,无论我做什么,都会出现一些错误。我让它只与底座一起工作,但是当我尝试实现时,甚至底座都没有下划线,并且有些东西不起作用。
我正在尝试成功创建一个声明性宏,它接受给定的内容并从 Enum 返回一个对象 我尝试使用不同的变量属性更改变量属性,例如 expr、tt、literal、item 以及可能的其他属性,但我就是无法使其工作。
你的第一个宏臂是正确的。您可以指定要匹配的标记,甚至可以添加括号,就像您所做的那样。
错误出在你的第二只手臂上。您试图将
not(base('A'))
之类的内容与 not($inner:tt)
相匹配,这是不正确的。原因是,base('A')
根本就不是一个单独的tt
。
解决你的问题的最原始的解决方案看起来像这样:
macro_rules! expr_enum {
( base ( $ch:expr ) ) => {{
Enum::Base($ch)
}};
( not ( $inner:tt ( $ch:expr ) ) ) => {{
Enum::Not(
Box::new(
expr_enum!($inner($ch))
)
)
}};
}
您必须明白
base(expr)
不是tt
。它实际上是一个tt tt expr tt
。每个标记都与 tt
匹配。
但是,由于您想要括号,您可以进一步指定它们:
tt ( expr )
。
现在,通过捕获第二个臂内的参数列表,您将能够以任意深度嵌套
not
指令。
macro_rules! expr_enum {
( base( $ch:expr ) ) => {{
Enum::Base($ch)
}};
( not ( $inner:tt ( $($args:tt)* ) ) ) => {{
Enum::Not(
Box::new(
expr_enum!($inner($($args)*))
)
)
}};
}
说明:
模式
not( $inner:tt ( $($args:tt)* ) )
将匹配具有带有任意参数的嵌套 not
指令的外部 inner
指令。之后,它将调用自身,但这一次,inner
指令将成为外部指令,并且它会执行此操作,直到找到base
指令。
一个例子可以更好地说明这一点:
not(base('A'))
:not
关键字和(
标记与宏模式的第一部分匹配。然后,嵌套的 base
关键字和后面的 (
标记将通过 $inner:tt (
进行匹配。然后,inner
(又名 base
)内的任何内容都与 $($args:tt)*
匹配。此语法意味着零个或多个标记。最后,剩余的 )
标记被匹配。
not(not(not(base('A'))))
:与第一个示例类似,但 not
指令嵌套得更深。第一个 not(
与宏模式的第一部分匹配。然后第二个 not(
与 $inner:tt (
匹配。然后,第二个 not
中的任何内容都与 $($args:tt)*
匹配。最后,剩余的 )
标记被匹配。
第二个宏臂以
$inner($($args)*)
作为参数调用自身。对于 not(not(not(base('A'))))
,内部 not(not(base('A')))
将被传递。然后not(base('A'))
,最后base('A')
,完成递归。