在上一篇 Rust 声明式宏中的 Metavariables 有哪些 的基础上,

今天尝试解析一下 Rust 中的几种 item。我们知道一个 crate 是由 item 组成的,每一个 fn struct enum impl mod 等定义都是一个 item,

这篇文章就简单解析一下 Function 和 struct

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 语法的更多相关文章

  1. DEVOPS技术实践_08:声明式管道语法

    简介 前面简单的做了管道的实验,看了一下的它的效果 声明式管道是Groovy语法中的一个更简单和结构化的语法.下面主要学习明式管道语法. 一 声明式管道的基本结构 以上节的代码为例 node { de ...

  2. Jenkins教程——从安装到部署Docker服务(二)声明式流水线HelloWorld

    前言 本文通过一个声明式流水线的HelloWorld程序做一下流水线基础入门,对常用的流水线参数进行简要说明 什么是流水线 现实中的流水线 流水线比较好理解,类比于现实生活中的生产流水线,每个流程只做 ...

  3. 【Kubernetes】深入解析声明式API

    在Kubernetes中,一个API对象在Etcd里的完整资源路径,是由:Group(API组).Version(API版本)和Resource(API资源类型)三个部分组成的. 通过这样的结构,整个 ...

  4. Jenkins pipeline声明式语法

    目录 一.最简结构 二.简单例子 一.最简结构 pipeline {     agent any     stages {         stage('pull') {             st ...

  5. spring声明式事务管理详情解析

    前沿:通过对spring事务管理有了比较深入学习,本文将不做实例,而是指定具体的类和配置文件进行讲解. 本文内容: 1.了解什么是声明式事务? 2.声明式事务管理分别有哪几种? 3.这几种事务管理之间 ...

  6. spring5 源码深度解析----- @Transactional注解的声明式事物介绍(100%理解事务)

    面的几个章节已经分析了spring基于@AspectJ的源码,那么接下来我们分析一下Aop的另一个重要功能,事物管理. 事务的介绍 1.数据库事物特性 原子性多个数据库操作是不可分割的,只有所有的操作 ...

  7. spring cloud深入学习(四)-----eureka源码解析、ribbon解析、声明式调用feign

    基本概念 1.Registe 一一服务注册当eureka Client向Eureka Server注册时,Eureka Client提供自身的元数据,比如IP地址.端口.运行状况指标的Uri.主页地址 ...

  8. How Javascript works (Javascript工作原理) (十四) 解析,语法抽象树及最小化解析时间的 5 条小技巧

    个人总结:读完这篇文章需要15分钟,文章介绍了抽象语法树与js引擎解析这些语法树的过程,提到了懒解析——即转换为AST的过程中不直接进入函数体解析,当这个函数体需要执行的时候才进行相应转换.(因为有的 ...

  9. JavaScript在页面中的执行顺序(理解声明式函数与赋值式函数) 转载

    JavaScript在页面中的执行顺序 https://blog.csdn.net/superhoy/article/details/52946277 2016年10月27日 15:38:52 阅读数 ...

  10. 关于CSS自文档的思考_css声明式语言式代码注释

    obert C. Martin写的<Clean Code>是我读过的最好的编程书籍之一,若没有读过,推荐你将它加入书单. 注释就意味着代码无法自说明 —— Robert C. Martin ...

随机推荐

  1. Vue指令:内置指令和自定义指令

    Vue指令 Vue指令指的是,以v-开头的一组特殊语法 内置指令 v-text v-text指令的作用是:设置标签的内容 默认写法会替换全部内容,差值表达式{{ }}只会替换指定内容 内部支持写表达式 ...

  2. 面试题锦集:1、数据库三大范式,2、mysql索引类型及作用,3、事务的特性和隔离级别

    目录 面试题集锦 一.数据库三大范式 二.mysql有哪些索引类型及作用 三.事务的特性和隔离级别 1.事务的四大特性 2.事务的隔离级别 3.什么是脏读.不可重复度.幻读 4.解决办法 面试题集锦 ...

  3. 在k8s上安装Harbor

    在k8s上安装Harbor 先前条件 <kubernetes(k8s) 存储动态挂载><在k8s(kubernetes)上安装 ingress V1.1.3> 参考我之前的文档 ...

  4. [Android]ADB调试: SecurityException: Injecting to another application requires INJECT_EVENTS permission

    问题描述 使用ADB工具调试安卓设备时报此错误: C:\Users\Johnny>adb shell input text "Hello" java.lang.Securit ...

  5. JVM:并发的可达性分析

    当前主流编程语言的垃圾收集器基本上都是依靠可达性分析算法来判定对象是否存活的,可达性分析算法理论上要求全过程都基于一个能保障一致性的快照中才能够进行分析,这意味着必须全程冻结用户线程的运行. 在根节点 ...

  6. Go For Web:踏入Web大门的第一步——Web 的工作方式

    前言: 本文作为解决如何通过 Golang 来编写 Web 应用这个问题的前瞻,对 Golang 中的 Web 基础部分进行一个简单的介绍.目前 Go 拥有成熟的 Http 处理包,所以我们去编写一个 ...

  7. vulnhub靶场之CROSSROADS: 1

    准备: 攻击机:虚拟机kali.本机win10. 靶机:Crossroads: 1,下载地址:https://download.vulnhub.com/crossroads/crossroads_vh ...

  8. 虚拟内存与malloc/new原理详解

    malloc malloc()函数并不是系统调用,而是 C 库里的函数,用于动态分配内存.malloc() 分配的是虚拟内存,而不是物理内存.如果分配后的虚拟内存没有被访问的话,是不会将虚拟内存映射到 ...

  9. T-SQL基础教程Day3

    第三章 联接3.1交叉联接交叉联接是最简单的联接类型.交叉联接仅执行一个逻辑查询处理阶段--笛卡尔乘积将一个输入表的每一行与另一个表的所有行匹配SQL Server支持交叉联接的两种标准语法:ANSI ...

  10. R读入数据

    两种方式: edit()自动生成一个红色的表格,列名会自动的放上去,不够的会显示var5,var6,var7 mydata <- data.frame( age = numeric(0), ge ...