Есть ли способ настроить приведенный ниже макрос, чтобы определить, когда последний аргумент вызова макроса является замыканием? Код ниже работает, но для устранения неоднозначности используется точка с запятой, и это выглядит неправильно.
Может ли аргумент закрытия быть идентифицирован конкретно при вызове, например. closure: || { ... }
?
macro_rules! invoke_me {
($func_name:ident, $($arg:expr),*; || $closure:expr ) => {{
println!("{}({})", stringify!($func_name), stringify!($($arg),*));
println!("With closure");
let result: Result<(),String> = $closure;
result
}};
($func_name:ident, $($arg:expr),*) => {{
println!("{}({})", stringify!($func_name), stringify!($($arg),*));
println!("No closure");
Ok::<(),String>(())
}};
}
fn main() {
invoke_me!(foo, 1, 2, 3).unwrap();
invoke_me!(foo, 1, 2, 3; || {
println!("Ok from closure");
Ok(())
}).unwrap();
let _ = invoke_me!(foo, 1, 2, 3; || {
println!("Error from closure");
Err("Error".to_string())
});
}
Используем идею из Как отделить последнее выражение в повторяющихся выражениях в макросе Rust? (см. комментарий ChrisB), у меня это работает:
macro_rules! invoke_me {
($func_name:expr, $($rest:tt)+) => {
invoke_me!(@transpose $func_name, [ ] $($rest)+)
};
(@transpose $func_name:expr, [ $($args:expr)*] || $closure:expr) => {{
println!("{}({})", stringify!($func_name), stringify!($($args),*));
println!("With closure");
let result: Result<(),String> = $closure;
result
}};
(@transpose $func_name:expr, [$($temp:expr)*] $arg:expr , $($rest:tt)+) => {
invoke_me!(@transpose $func_name, [$($temp)* $arg] $($rest)+)
};
(@transpose $func_name:expr, [$($args:expr)*] $last_arg:expr) => {{
println!("{}({})", stringify!($func_name), stringify!($($args),*, $last_arg));
println!("No closure");
Ok::<(),String>(())
}}
}
fn main() {
invoke_me!(foo, 1, 2, 3).unwrap();
invoke_me!(foo, 1, 2, 3, || {
println!("Ok from closure");
Ok(())
}).unwrap();
let _ = invoke_me!(foo, 1, 2, 3, || {
println!("Error from closure");
Err("Error".to_string())
});
}
Хотя это возможно, вероятно, было бы лучше просто оставить точку с запятой, поскольку это медленно.
Большое спасибо, что поделились этой техникой. Это действительно работает! Я предполагаю, что вы имеете в виду медленное время компиляции, поскольку макрос рекурсивный.
это может вам помочь: stackoverflow.com/questions/75203742/… вероятно, придется tt/expr munch, чтобы разделить последнее выражение, а затем сопоставить шаблон при замыкании.