网站首页 > 博客文章 正文
宏的分类
1)宏按照来源分类
声明宏(Declarative Macro)和过程宏(Procedural Macro)。
前者指的是用某种语法直接声明出的宏。
后者是对应直接生成抽象语法树的过程的宏。
2)宏按照使用方式分类
属性宏:给声明添加属性的宏,例如 #[derive(Debug)] 和 #[test]。
调用宏:像函数一样的宏,例如 println!。
3)来源分类与使用分类直接关系
明宏都是用 macro_rules! 声明出的,它声明出的一定是调用宏。过程宏可以产生属性宏,也可以产生调用宏,也就是说,属性宏都是过程宏,调用宏可能是声明宏或者过程宏。
宏的定义
使用 macro_rules!进行自定义
常用的println()宏的大概形式:
macro_rules! println {
() => (println!("\n"));
($fmt: expr) => (print!(concat!($fmt, "\n")));
($fmt: expr, $($(arg:tt)*) =>
(print!(concat!($fmt, "\n"), $($arg)*));
}
1) 组成部分
有三个部分,输入分别是 ()、($fmt:expr) 和 ($fmt: expr, $($args:tt)*),依次扩展成 => 后,圆括号内部的部分。每个部分是一条规则,每条规则以 ; 结尾。
其中=>后面的圆括号是必须存在的,不能省略。但可以写成{}或者[ ]形式。
- $fmt: expr $fmt 是对宏参数的捕获,类似于函数的参数
- expr 表示这个捕获的类型是表达式,也就是会它会生成具体的值
捕获有什么用?
宏的替换结果里可以用 $fmt 代表要替换这个捕获。例如 println!("Hello") 中,$fmt: expr 捕获了 "Hello",所以 print!(concat!($fmt, "\n)) 中的 $fmt 会被替换为 "Hello",所以展开成 print!(concat!("Hello", "\n"))。
展开的宏中如果还有宏,还会继续展开吗?
会,上面 println! 展开之后的内容中有 print! 和 concat!,它们都会再次展开。这是理所当然的行为,这个问题只是为了让 Rust 的宏跟 C++ 的宏划清界限。
都有什么捕获类型?
$($arg:tt)* 是什么意思?
单独看 $arg:tt 表示匹配一个词条树的捕获,在外面套上 $()* 表示匹配若干次词条树。
$($arg)* 是什么意思?
单看 $arg,表示在宏里替换捕获 $arg,外面套上 $()* 表示使用所有匹配的捕获。这个用法跟它的捕获语法是对应的。
$($arg:tt)* 能匹配什么?
println! 在第一个参数之后的所有东西。这个宏不止可以传递像函数一样的参数,还可以像 Python 那样传递命名参数,例如:
println!("Hello, {name}", name="Luna");
这样的参数 $($arg:tt)* 也能捕获到。
如果想只捕获(不定个数个)函数参数应该如何做?
用 $($arg: expr),* 或者 $($arg: expr,)*。
这两个有什么不同?
后者也匹配逗号结尾的参数列表。
Rust 的函数参数列表最后可以添加逗号,也可以不加。如果想让宏表现的尽量接近函数,应该两种情况都处理
具体案例
1) 定义个hash_map的宏
macro_rules! hash_map {
($($key:expr => $value:expr),*) => {{
let mut map = ::std::collections::HashMap::new();
$( map.insert($key, $value); )*
map
}};
($($key:expr => $value:expr),*) =>
(hash_map! ($($key => $value),*));
}
2)具体使用
macro_rules! hash_map {
($($key:expr => $value:expr),*) => {{
let mut map = ::std::collections::HashMap::new();
$( map.insert($key, $value); )*
map
}};
($($key:expr => $value:expr),*) =>
(hash_map! ($($key => $value),*));
}
fn main() {
let map = hash_map! (1 => "one", 2 => "two", 3 => "three");
println!("{:?}",map);
}
参考
作者:plus7wist
链接:https://ld246.com/article/1592390738395
猜你喜欢
- 2024-09-11 Rust 写操作系统之Hello world (三)
- 2024-09-11 Rust: 如何用Panic打造健壮应用(rust zig)
- 2024-09-11 在 Linux 新版内核中的 Rust 初探,原来是这样的
- 2024-09-11 Rust 向量(Vec)(rust 向量化)
- 2024-09-11 Rust 入坑指南:鳞次栉比 | CSDN 博文精选
- 2024-09-11 学习Rust编程——使用macro_rules!创建宏
- 2024-09-11 利用 Rust 过程宏实现的 derive-with 库
- 2024-09-11 Rust 基础入门-错误处理和宏-错误处理
- 2024-09-11 Rust 基础入门-错误处理和宏-属性式宏&函数式宏
- 2024-09-11 Rust中巧用matches!宏(rust腐蚀免费版)
你 发表评论:
欢迎- 最近发表
- 标签列表
-
- powershellfor (55)
- messagesource (56)
- aspose.pdf破解版 (56)
- promise.race (63)
- 2019cad序列号和密钥激活码 (62)
- window.performance (66)
- qt删除文件夹 (72)
- mysqlcaching_sha2_password (64)
- ubuntu升级gcc (58)
- nacos启动失败 (64)
- ssh-add (70)
- jwt漏洞 (58)
- macos14下载 (58)
- yarnnode (62)
- abstractqueuedsynchronizer (64)
- source~/.bashrc没有那个文件或目录 (65)
- springboot整合activiti工作流 (70)
- jmeter插件下载 (61)
- 抓包分析 (60)
- idea创建mavenweb项目 (65)
- vue回到顶部 (57)
- qcombobox样式表 (68)
- vue数组concat (56)
- tomcatundertow (58)
- pastemac (61)
本文暂时没有评论,来添加一个吧(●'◡'●)