首页 > 其他分享 >用声明式宏解析 Rust 语法

用声明式宏解析 Rust 语法

时间:2023-06-16 18:46:07浏览次数:57  
标签:name ty 语法 vis meta block fn 解析 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 的情况处理起来大同小异,我就不写了

标签:name,ty,语法,vis,meta,block,fn,解析,Rust
From: https://www.cnblogs.com/hangj/p/17486291.html

相关文章

  • golang 语法糖
    golang语法糖在Go语言中,nums...是一种语法糖,用于将切片nums展开为一个个独立的参数。在函数调用中,如果你有一个切片nums,你可以使用nums...将切片展开为独立的元素,作为函数的参数传递。以下是一个示例说明nums...的使用:gofuncsum(nums...int)int{total:......
  • 用python生成正玄波信号源码解析
    一前记项目需要生成不同频点的正玄波信号,没找到现成的软件,只能自己写一个了。顺便温习一下python。 二源码解析:#!/usr/bin/pythonimportnumpyasnpfromscipyimportsignalimportwaveimportstructimportsysnum_samples=48000sampling_rate=48000.0ampl......
  • FLASH-CH32x芯片FLASH读写保护解析
    一、flash的操作流程1、解锁芯片复位后默认会给控制寄存器FLASH_CTRL上锁,这个时候不允许设置FLASH的控制寄存器,从而不能修改FLASH的内容。所以每次对FLASH写入数据前,都需要先给它解锁。2、擦除擦除有几种方式:页擦除(256字节、32K、64K)、标准擦除(4K)、全擦,不同擦除方式擦除flash......
  • Doo Prime 德璞资本:怎么买美股?美股购买流程大解析
    怎么买美股?对新手投资者来说是一个相对复杂的命题。因为受到地域因素的限制,美股购买流程会相对复杂一些,每一个美股购买流程环节都有许多注意点。以下是美股购买流程大解析的相关内容。美股购买流程一、选择美股开户方式美股开户方式有两种,一是到美国开户,而是通过线上交易平台完成开......
  • html页面解析
    getElementsByTagName和getElementsByClassName这两个方法查找多个dom元素,返回的是htmlcollection类型,是伪数组而不是真数组,故不能使用数组的方法。我们可以使用数组原型配合slice方法,利用call,apply,bind方法将伪数组转为真数组。varx=document.getElementById("main......
  • .nupkg格式解析
    .nupkg格式是NuGet包的标准打包格式。NuGet是用于在.NET开发中共享和管理代码、工具和库的包管理器。.nupkg文件实际上是一个压缩文件,其内部包含了NuGet包的相关内容。下面是.nupkg文件的组成部分:__metadata:该文件夹包含与包相关的元数据信息,例如包的ID、版本号、......
  • python基础语法练习题
    """一、必做题1、下面变量名正确的是(ABD)A.nameB.num1C.1_numD.name_A_12、Python不支持的数据类型有(A)A、charB、intC、floatD、list3、python源程序执行的方式(B)A编译执行B解析执行C直接执行D边编译边执行4、Python语言语句块的标记是(C)A分号B......
  • Markdown语法学习记录
    ##小记markdown语法是写博客所需要的基本的语法,而且也比较容易掌握,以下是我个人学习的基础的语法。##标题一共有六级标题,先说一级标题一级标题的语法是#+空格+标题二级标题的语法是##+空格+标题 ......想创建多少级的标题就在前面加多少个#号##字体**粗体***斜体*......
  • Python学了基本语法 下一步该干什么 ?
    刚入门Python,学习了基本语法后,你可以开始编写简单的程序了。接下来,你可以学习Python的标准库和第三方库,掌握更多的编程技巧和知识,提高自己的编程能力。同时,也可以通过实践项目来巩固所学知识,提高自己的实战能力。学习Python基本语法是入门的第一步,接下来你可以考虑以下几个方向......
  • Verilog语法 - 阻塞赋值 & 非阻塞赋值
    参考https://zhuanlan.zhihu.com/p/720344011.非阻塞赋值代码如下always@(posedgeclk)beginb<=a;c<=b;endRTL会综合出两个寄存器串行,如下波形图所示,第一个时钟上升沿来临时,会把a的旧值赋值给b;同时,c获得的是b的旧值,而不是从a那里拿到的新值。非阻......