本笔记总结自The Little Book of Rust Macros
我对其中的案例有所简化
bilibili不支持markdown是真的难顶
(相关资料图)
概述
宏的种类
Attributes
内置宏 built-in
过程宏 proc-macro
派生宏 derive
函数式的宏
AKA 类函数宏
macro_rules!
宏的变种,一般只考虑macro_rules!
这一个宏
宏展开
很像 C 的 Define
,在编译时自动替换
rust 中的宏是在 AST 之后展开,自己会加括号,不会改变运算顺序
卫生性
hygiene
一个概念,简单理解为:宏不应该隐式地改变或创建变量
比如一个宏,用户没有传入变量a
,但它把a
的值改变了;或者它创建了变量b
,但始终没有move或drop,就不卫生
调试
rustc +nightly -Zunpretty=expanded hello.rs
思路
基本语法
expansion
也可以叫做 transcriber
matcher
匹配()
或胡言乱语
匹配元变量
该例中,matcher
为 $($elem: expr),*
元变量
有一个特殊的元变量叫做 $crate
,它用来指代当前 crate 。
小例子:
反复
repetition
语法:
$(...) sep rep
其中:
$
: a token (token意为标记)
(...)
: the matcher which need repetition
sep
: an optional separator token; example:,
;
rep
:
?:
appear zero or one time
*:
appear any times
+:
appear once or more
Example:
多个变量的情况:
macro metavariable expressions
Unstable now (2023.3.27) and we can not use it in a stable channel
实战
斐波纳切数列
构建步骤
确定调用形式
确定想要生成的代码
改善调用形式
初步构建
替换
测试
导出
确定调用形式
据此,初步构建宏:
依次匹配:
字面量:a[n] =
一个及以上的表达式(expr)
字面量:, ... ,
一个表达式(expr),本例中,此为通式
确定想要生成的代码
改善调用形式
在 coding 的过程中发现,用户可能需要能够自定义迭代器中Item
的类型
故修改宏的调用形式为:
据此初步构建宏:
初步构建
将前面几个步骤的结果组合在一起
cargo test
这是由于在某次版本更新后, expr
之后只能跟随 =>
、,
、;
之一
故解决方法为用 ;...;
代替 ,...,
,修改以下两行:
当前完整代码:
替换
完成后:
cargo test
据说在 nightly 版本中,可以编译通过。此处不通过的原因在于,测试中的 a
和 n
与宏中的 a
和 n
具有不同的上下文,解决方法是:
这样,rustc 才能推断出 a
和 n
是 ident
(identifier)
其他测试
导出宏
完整代码
关键词: