我正在尝试编写一个宏来扩展它:
let res = log_request_response!(client.my_call("friend".to_string(), 5));
Run Code Online (Sandbox Code Playgroud)
进入这个:
let res = {
debug!("Request: {}", args_separated_by_commas);
let res = client.my_call("friend".to_string(), 5);
debug!("Response: {}", res);
res
};
Run Code Online (Sandbox Code Playgroud)
到目前为止我的尝试是这样的:
#[macro_export]
macro_rules! log_request_response_to_scuba {
($($client:ident)?.$call:ident($($arg:expr),*);) => {
let mut s = String::new();
$(
{
s.push_str(&format!("{:?}, ", $arg));
}
)*
s.truncate(s.len() - 2);
debug!("Request: {}", s);
// Somehow reconstruct the entire thing with res = at the start.
debug!("Response: {}", res);
res
};
}
Run Code Online (Sandbox Code Playgroud)
但这无法编译:
error: macro expansion ignores token `{` and any following
--> src/main.rs:10:13
|
10 | {
| ^
...
39 | let res = log_request_response_to_scuba!(client.my_call(hey, 5));
| ------------------------------------------------------ caused by the macro expansion here
|
= note: the usage of `log_request_response_to_scuba!` is likely invalid in expression context
Run Code Online (Sandbox Code Playgroud)
如果我删除和匹配.之间的内容,它会引发有关模糊匹配的不同错误(这是有道理的)。clientcall
所以我的第一个具体问题是如何匹配点?对我来说,这场比赛看起来是正确的,但显然不是。
除此之外,任何帮助制作一个可以实现我想要的功能的宏都会很棒。如果它是正则表达式我只想这样:
.*\((.*)\).*
Run Code Online (Sandbox Code Playgroud)
我只是捕获括号内的内容并将它们分开。然后我使用第 0 个捕获组来获取整个内容。
谢谢!
错误消息并不是因为您以某种方式错误地匹配了点,而是因为您没有返回表达式。你想返回这个:
\n{\n debug!("Request: {}", args_separated_by_commas);\n let res = client.my_call("friend".to_string(), 5);\n debug!("Response: {}", res);\n res\n};\nRun Code Online (Sandbox Code Playgroud)\n但是,您的宏当前返回的内容与此更类似:
\ndebug!("Request: {}", args_separated_by_commas);\nlet res = client.my_call("friend".to_string(), 5);\ndebug!("Response: {}", res);\nres\nRun Code Online (Sandbox Code Playgroud)\n请注意缺少的花括号。通过将完整的转录器部分括在大括号中,可以很容易地解决这个问题。
\n我不确定为什么client在你的匹配器中是可选的。我假设您希望有选择地允许宏的用户对某个变量调用函数或方法。那是对的吗?如果是,那么您的代码当前不允许 \xe2\x80\x93 与client.my_call(...)以及匹配.some_function(...),但不允许some_function(...)(请注意从开头删除的空格)。要执行您想要的操作,您可以匹配$variable:ident$(.$field:ident)?\xe2\x80\x93 请注意,这里的点也是可选的 \xe2\x80\x93 ,甚至更好地$variable:ident$(.$field:ident)*允许在 loval 变量的字段的字段上调用方法(所以,类似的东西variable.sub_struct.do_something()。
生成的代码带有一些示例:
\nmacro_rules! log_request_response {\n ($variable:ident$(.$field:ident)*($($arg:expr),*)) => {\n {\n let mut s = String::new();\n $(\n {\n s.push_str(&format!("{:?}, ", $arg));\n }\n )*\n s.truncate(s.len() - 2);\n // using println! here because I don\'t want to set up logging infrastructure\n println!("Request: {}", s);\n let res = $variable$(.$field)*($($arg),*);\n println!("Response: {}", res);\n res\n }\n };\n}\n\nfn test_func(_: String, i: i32) -> i32 {\n i\n}\n\nstruct TestStruct;\n\nimpl TestStruct {\n fn test_method(&self, _: String, i: i32) -> i32 {\n i\n }\n}\n\nfn main() {\n let _ = log_request_response!(TestStruct.test_method("friend".to_string(), 5));\n let _ = log_request_response!(test_func("friend".to_string(), 5));\n}\nRun Code Online (Sandbox Code Playgroud)\n\n