我想写一个声明性宏:
log!("{} {} {}", private!(1), public!(2), 3);
out : <private>2<private>
如果参数不是add "public"或add "private"宏,则将参数打印为"",
我的代码:
macro_rules! log {
($($arg:tt)*) => {
let log_str = format!($($arg)*);
println!("{}", log_str);
};
}
macro_rules! private {
($arg:tt) => {
"<private>"
};
}
macro_rules! public {
($arg:tt) => {
$arg
};
}
fn main() {
log!("{} {} {}", private!(1), public!(2), 3);
}
但是我不知道如何为第三默认参数设置"私有"属性,
我尝试使用类似函数的宏来解析日志宏中的参数,但它非常复杂,您能帮助我吗
1条答案
按热度按时间hmae6n7t1#
宏观设计
您可以使用递归宏by-example,通过单独处理每个参数来构建
format!
字符串参数列表。宏的递归算法需要保留以下内容:
在每一步中,宏从尚未处理的参数列表中删除第一个参数,处理它,并将已处理的参数添加到已处理的参数列表的末尾。然后,它使用这些修改后的列表递归地调用自身。当只剩下一个未处理的参数时,调用基本情况;当剩下多个未处理的参数时,调用递归情况。
在处理一个论点时,我们需要考虑三种情况:
private!(expr)
:表达式expr
给定的私有参数,必须替换为"<private>"
public!(expr)
:表达式expr
给定的公共参数,必须按原样打印expr
:表达式expr
给定的未标记参数,默认情况下必须假定为私有对于上面列出的三种类型的参数,宏都有一个递归大小写和一个基本大小写。但是,每个基本大小写和递归大小写遵循相同的模式-唯一的区别是如何处理参数。
实施
递归
@rec
规则具有以下参数规范:宏的公共API规则只是构建适当的参数列表,并将它们转发给递归
@rec
规则。注意,基本case规则和
@call
规则中的$(,)
匹配器片段用于捕获第一次递归case调用(当processed_args
列表为空时)产生的尾随逗号。用法
此宏完全按照您的问题中指定的方式使用:
使用
private!(arg)
来表示私有参数,使用public!(arg)
来表示公共参数(即使这些宏在技术上并不存在)。由于public!
和private!
实际上并不作为独立宏存在,因此您可以选择使用不那么容易混淆的语法,例如@private arg
和@public arg
。Playground