首先, 我感觉 Rust 的宏是非常强大的, 可以根据 match 有不同的实现,但是它也是极其让人,起码是让我纠结的和费解的, 我希望能够一点点的弄懂他
// 定义宏的语法
macro_rules! vec {
// 这里的 * 感觉是一种连续的匹配值
( $( $x:expr ),* ) => {
{
let mut temp_vec = Vec::new();
// $()*的语法在我看来就是一种迭代器,让我们迭代所有的匹配结果
$(
temp_vec.push($x);
)*
temp_vec
}
};
}
在一些复杂的宏中, 甚至用到了一些递归的写法
我们在 匹配的时候发现 匹配到的值后面有 :expr
, 文档中也给出了一系列规则
ident: 标识符,用来表示函数或变量名
expr: 表达式
block: 代码块,用花括号包起来的多个语句
pat: 模式,普通模式匹配(非宏本身的模式)中的模式,例如 Some(t), (3, 'a', _)
path: 路径,注意这里不是操作系统中的文件路径,而是用双冒号分隔的限定名(qualified name),如 std::cmp::PartialOrd
tt: 单个语法树
ty: 类型,语义层面的类型,如 i32, char
item: 条目,
meta: 元条目
stmt: 单条语句,如 let a = 42;
#[macro_use]
表示子模块的宏可以被父模块调用
#[macro_export]
表示可以被其他的 crate 调用
$crate 在宏中表示该模块
实例解析
error_chain 这个类库就是一个使用宏的范例,我们今天就来看一下
这个库的主要功能就是通过简单的设置,让宏来完成所有重复的代码
基本的实现就是 通过一步步的宏的迭代,把需要的参数排序并且解析出来,之后再通过解析出来的参数,组合并且返回相应的代码块,代码块中已经把 错误类型, 错误文档, 错误代码 全部都自动组合好
网友评论