用声明式宏解析 Rust 语法

在上一篇 Rust 声明式宏中的 Metavariables 有哪些 的基础上,
今天尝试解析一下 Rust 中的几种 item。我们知道一个 crate 是由 item 组成的,每一个 fn struct enum impl mod 等定义都是一个 item,
这篇文章就简单解析一下 Functionstruct

Function

先看一个最简单的函数

fn foo() {} 

这个 foo 函数由关键字 fn 开头,后面跟一个函数名($function_name: ident), 然后是一对 (), 再跟一个函数体 block

macro_rules! function_item_matcher {     (fn $name: ident () $block: block) => {         fn $name() $block     }; }  function_item_matcher! {     fn hello(){         println!("hello");     } } 

再复杂一点,给我们的 foo 函数加点料

#[allow(unused_variables)] pub async fn foo(arg1: u8) -> u8 { arg1 } 

我们的 foo 函数已经具备了常见函数的基本形态,除了没有泛型等比较复杂的部分,这里了解分析方法就行,有需要的话再继续抽丝剥茧即可。
完整的 Function 的语法定义看这里: https://doc.rust-lang.org/reference/items/functions.html

macro_rules! function_item_matcher {     (         #[$meta: meta]         $vis: vis async fn $name: ident ($arg: ident : $ty: ty) -> $ret:ty $block: block     ) => {         #[$meta]         $vis async fn $name($arg: $ty) -> $ret $block     }; } 

如果 meta 的个数和 argument 的个数都不确定呢

#[allow(unused_variables)] #[allow(dead_code)] pub async fn foo(arg1: u8, arg2: u32, ) -> u8 { arg1 } 

好,那就再改一改:

macro_rules! function_item_matcher {     (         $(#[$meta: meta])*         $vis: vis async fn $name: ident ($($arg: ident : $ty: ty),* $(,)?) -> $ret:ty $block: block     ) => {         $(#[$meta])*         $vis async fn $name($($arg: $ty),*) -> $ret $block     }; } 

还有个问题,这个 async 直接写下来的,要是没有 async 呢? 只需要加一个分支就好

macro_rules! function_item_matcher {     (         $(#[$meta: meta])*         $vis: vis async fn $name: ident ($($arg: ident : $ty: ty),* $(,)?) -> $ret:ty $block: block     ) => {         $(#[$meta])*         $vis async fn $name($($arg: $ty),*) -> $ret $block     };      (         $(#[$meta: meta])*         $vis: vis fn $name: ident ($($arg: ident : $ty: ty),* $(,)?) -> $ret:ty $block: block     ) => {         $(#[$meta])*         $vis fn $name($($arg: $ty),*) -> $ret $block     }; } 

这样做不过是把我定义的函数照搬下来,有什么好处呢?好处就是你可以随意插入自己的代码

macro_rules! function_item_matcher {     (         $(#[$meta: meta])*         $vis: vis fn $name: ident ($($arg: ident : $ty: ty),* $(,)?) -> $ret:ty $block: block     ) => {         println!("definition: {}({})", stringify!($name), stringify!($($arg: $ty),*));         $(#[$meta])*         $vis fn $name($($arg: $ty),*) -> $ret {             print!("calling: {}(", stringify!($name));             $(print!("{},", $arg);)*             println!(")");              $block         }     }; }  function_item_matcher!{     #[allow(unused_variables)]     #[allow(dead_code)]     pub fn foo(arg1: u8, arg2: u32, ) -> u8 { arg1 } }  foo(9, 8); 

输出

definition: foo(arg1 : u8, arg2 : u32) calling: foo(9,8,) 

struct

struct 有两种

// struct struct #[...] struct A {     ... }  // tuple struct #[...] struct B(...); 

所以对于第一种:

macro_rules! struct_item_matcher {     (         $(#[$meta: meta])*         $vis: vis struct $name: ident {             $(                 $(#[$field_meta: meta])*                 $field_vis: vis $field_name: ident : $field_ty: ty             ),*              $(,)?         }     ) => {         $(#[$meta])*         $vis struct $name {             $(                 $(#[$field_meta])*                 $field_vis $field_name: $field_ty             ),*         }     };      // 针对 struct A; 的情况     (         $(#[$meta: meta])*         $vis: vis struct $name: ident;     ) => {         $(#[$meta])*         $vis struct $name;     } } 

对于第二种 tuple struct 的情况处理起来大同小异,我就不写了 😂

用声明式宏解析 Rust 语法

发表评论

评论已关闭。

相关文章

  • 0