• 用声明式宏解析 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 的情况处理起来大同小异,我就不写了 😂

  • 相关阅读:
    详情页返回列表页,列表状态缓存
    python音频转文字调用baidu
    2024.06.03 校招 实习 内推 面经
    645仪表以JSON格式上发方法
    数据中台:数据采集和抽取的技术栈详解
    SpringBoot+Vue项目漫画之家系统
    middlebury立体匹配评估使用方法总结(一)
    记一次服务宕机、优化全流程(以后也可以装X了)
    vue2、vue3、react响应式原理、组件声明周期阐述与对比
    社区型商场/购物中心会员管理方案
  • 原文地址:https://www.cnblogs.com/hangj/p/17486291.html