我想使用宏来模拟 cpp 中的捕获规则作为学习练习,并且我意识到 rustfmt 并不总是很好用。我还想知道是否有一种方法可以简化或使用特定技术来降低宏规则的复杂性。就像宏规则是否有标准形式一样。
这是有问题的宏:
macro_rules! capture {
([$($tail:tt)*] $expression:expr) => (
{
capture![$($tail)*];
$expression
}
);
[mut $value:ident, $($tail:tt)*] => {
let mut $value = $value.clone();
capture![$($tail)*];
};
[mut $value:ident] => {
let mut $value = $value.clone();
};
[$value:ident, $($tail:tt)*] => {
let $value = $value.clone();
capture![$($tail)*];
};
[$value:ident] => {
let $value = $value.clone();
};
[$name:tt = $value:expr, $($tail:tt)*] => {
let $name = $value;
capture![$($tail)*];
};
[$name:tt = $value:expr] => {
let $name = $value;
};
[mut $name:tt = $value:expr, $($tail:tt)*] => {
let mut $name = $value;
capture![$($tail)*];
};
[mut $name:tt = $value:expr] => {
let mut $name = $value;
};
}
可以像下面这样使用:
#[test]
fn test_capture() {
let a = String::from("hello");
let b = String::from("world");
let x = capture!([mut a, b, c = 42] move || a.clone() + &b + &c.to_string() );
let _ = a;
let _ = b;
let _ = x();
let _ = x();
println!("{:?}", x());
}
我尝试通过创建一个逗号分隔的列表来减少宏规则,类似于
vec
宏,但 vec 宏采用同质的 expr 列表,我相信这使得问题变得更简单。相反,我的问题希望能够接受不同类型的令牌模式,但这会导致大量样板文件。
您可以做的一件事是避免通过零或一次重复来重复尾部和非尾部规则:匹配
$(...)?
并使用 $(...)*
扩展。这至少将您的规则简化为 DSL 的主要形式:
macro_rules! capture {
([$($tail:tt)*] $expression:expr) => (
{
capture![$($tail)*];
$expression
}
);
[mut $value:ident $(, $($tail:tt)*)?] => {
let mut $value = $value.clone();
$(capture![$($tail)*];)*
};
[$value:ident $(, $($tail:tt)*)?] => {
let $value = $value.clone();
$(capture![$($tail)*];)*
};
[$name:tt = $value:expr $(, $($tail:tt)*)?] => {
let $name = $value;
$(capture![$($tail)*];)*
};
[mut $name:tt = $value:expr $(, $($tail:tt)*)?] => {
let mut $name = $value;
$(capture![$($tail)*];)*
};
}
至于更“系统”的东西......呃不,不是真的。我想不到。您也可以查看
tracing::event
宏,看到它也有许多非常相似的手臂。