快捷搜索:  汽车  科技

rust宏语法(Rust之自定义宏写法)

rust宏语法(Rust之自定义宏写法)明宏都是用 macro_rules! 声明出的,它声明出的一定是调用宏。过程宏可以产生属性宏,也可以产生调用宏,也就是说,属性宏都是过程宏,调用宏可能是声明宏或者过程宏。3)来源分类与使用分类直接关系2)宏按照使用方式分类属性宏:给声明添加属性的宏,例如 #[derive(Debug)] 和 #[test]。调用宏:像函数一样的宏,例如 println!。

宏的分类

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 的宏划清界限。

都有什么捕获类型?

rust宏语法(Rust之自定义宏写法)(1)

$($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

猜您喜欢: