rust - 如何匹配宏中的点并重建原始令牌集?
问题描述
我正在尝试编写一个宏来扩展它:
let res = log_request_response!(client.my_call("friend".to_string(), 5));
进入这个:
let res = {
debug!("Request: {}", args_separated_by_commas);
let res = client.my_call("friend".to_string(), 5);
debug!("Response: {}", res);
res
};
到目前为止,我的尝试是这样的:
#[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
};
}
但这无法编译:
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
如果我删除和匹配.
之间的中间,它会抛出一个关于不明确匹配的不同错误(这是有道理的)。client
call
所以我的第一个重要问题是我如何匹配一个点?对我来说,这场比赛看起来是正确的,但显然不是。
除此之外,制作一个可以满足我要求的宏的任何帮助都会很棒。如果它是一个正则表达式,我只想要这个:
.*\((.*)\).*
我只是捕获括号内的东西并将它们分开。然后我使用第 0 个捕获组来获取整个内容。
谢谢!
解决方案
错误消息不是因为您以某种方式错误地匹配点,而是因为您没有返回表达式。你想返回这个:
{
debug!("Request: {}", args_separated_by_commas);
let res = client.my_call("friend".to_string(), 5);
debug!("Response: {}", res);
res
};
但是,您的宏当前返回更类似于此的内容:
debug!("Request: {}", args_separated_by_commas);
let res = client.my_call("friend".to_string(), 5);
debug!("Response: {}", res);
res
注意缺少的花括号。这可以很容易地通过将完整的转录器部分包含在大括号中来解决。
我不确定为什么client
在你的匹配器中是可选的。我假设您希望有选择地允许宏的用户调用某个变量的函数或方法。那是对的吗?如果是,那么您的代码当前不允许这样做 - 它匹配client.my_call(...)
以及.some_function(...)
,但不是some_function(...)
(注意从开头删除的空格)。为了做你想做的事,你可以匹配$variable:ident$(.$field:ident)?
——注意点在这里也是可选的——或者甚至更好$variable:ident$(.$field:ident)*
地允许在一个 loval 变量的字段的字段上调用一个方法(所以,像variable.sub_struct.do_something()
.
生成的代码带有一些示例:
macro_rules! log_request_response {
($variable:ident$(.$field:ident)*($($arg:expr),*)) => {
{
let mut s = String::new();
$(
{
s.push_str(&format!("{:?}, ", $arg));
}
)*
s.truncate(s.len() - 2);
// using println! here because I don't want to set up logging infrastructure
println!("Request: {}", s);
let res = $variable$(.$field)*($($arg),*);
println!("Response: {}", res);
res
}
};
}
fn test_func(_: String, i: i32) -> i32 {
i
}
struct TestStruct;
impl TestStruct {
fn test_method(&self, _: String, i: i32) -> i32 {
i
}
}
fn main() {
let _ = log_request_response!(TestStruct.test_method("friend".to_string(), 5));
let _ = log_request_response!(test_func("friend".to_string(), 5));
}
推荐阅读
- python - 为什么语法“main.py < input.txt”不起作用
- javascript - Chrome 扩展计时器并行实例和端口连接问题
- python - 熊猫检测过日日期
- kubernetes - 动态配置kubelet但不起作用,kubelet陷入自动重启循环,节点为NotReady
- python - 自动化 - 从 datepicker 抓取网页
- google-apps-script - 使用 google sheet 在 google drive 上显示文件更新
- python - 如何使用 Python (200 GB+) 从长 csv 文件的中间读取块
- excel - 根据具有特定范围日期时间的文件名打开excel文件(一一)
- laravel-livewire - Livewire/Alpine Dynamic # of Toggle Binding
- macos - 使用 Homebrew 安装 ifuse 会导致错误消息