什么是“Rust语言符号”?当编译器开始编译一个程序时,它首先读入源代码文件。为了简单起见,我们假设编译器将源代码存储在一个字符串中。下一步是逐个字符地遍历字符串,并将其划分为“标记”。
let foo: u32 = 30;
[
KeywordLet,
Identifier("foo"),
Colon,
Identifier("u32"),
SingleEquals,
NumericLiteral("30"),
Semicolon,
]
注意,这是一个完全虚构的例子。
Rust宏可以添加新代码:添加trait实现、创建新结构、编写新函数等。
1macro_rules! my_macro {
2 ($a: ident => $b: expr) => {
3 fn $a() {
4 println!("{}", $b);
5 }
6 };
7 ($a: ident, $b: expr) => {
8 println!("{} {}", $a, $b);
9 };
10}
一个标识符和一个用箭头(=>)分隔的表达式
用逗号分隔的标识符和表达式
1my_macro!(foo, 45);
2my_macro!(bar => "hello");
3my_macro!(baz => 9 * 8);
1json!({
2 "id": 42,
3 "name": {
4 "first": "John",
5 "last": "Zoidberg",
6 },
7});
1json!({
2 "id": 21 + 21, // Computed expression
3 "name": json!({ // This is another macro invocation!
4 "first": "John",
5 "last": "Zoidberg",
6 }),
7});
1macro_rules! andor {
2 ($a: ident ^ $b: ident $($tail: tt)*) => {
3 $a && andor!($b $($tail)*) // Recursive invocation
4 };
5 ($a: ident v $b: ident $($tail: tt)*) => {
6 $a || andor!($b $($tail)*) // Recursive invocation
7 };
8 ($($a: tt)*) => {
9 $($a)*
10 }
11}
12
13andor!(true ^ false v false ^ true) // true && false || false && true
14// => false
过程宏使用普通的Rust代码(不是唯一的语法)编写,经过编译,然后在调用时由编译器运行。由于这个原因,过程宏有时也被称为“编译器插件”。
[lib]
proc-macro = true
#[my_attribute_macro]
struct MyStruct; // This struct is the input to the macro
struct AnotherStruct; // This struct is not part of the macro's input
#[derive(MyDeriveMacro)]
struct MyStruct; // This struct is the input to the macro
struct AnotherStruct; // This struct is not part of the macro's input
my_function_like_macro!(arbitrary + token : stream 00);
// is the same as
my_function_like_macro![arbitrary + token : stream 00];
// is the same as
my_function_like_macro!{arbitrary + token : stream 00};
1use proc_macro::TokenStream;
2
3#[proc_macro_attribute]
4pub fn my_attribute_macro(attr: TokenStream, item: TokenStream) -> TokenStream {
5 todo!("Good luck!")
6}
#[my_attribute_macro]
struct AnnotatedItem;
在本例中,attr标记流将为空,而item标记流将包含AnnotatedItem struct。
#[my_attribute_macro(attribute_tokens)]
fn my_function() {}
在本例中,attr标记流将包含attribute_tokens,而item标记流将包含my_function函数。
我们已经建立了基本的基础设施,现在我们只需要解析输入的标记流。
https://geeklaunch.net/blog/fathomable-rust-macros/#procedural-macros