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

  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. Prometheus服务发现之kubernetes_sd_config

    一.为什么要使用Prometheus服务发现 之前我们讲过通过配置prometheus-operator的CRD ServiceMonitor来达到K8S集群相关组件和微服务的监控的目的,可以在Ser ...

  2. window.onload / onscroll/onresize 事件

    onload当文档加载完成后执行一些操作 window.onload = function(){ console.log("页面加载完成") } onscroll当页面发生滚动时执 ...

  3. 电商平台趋势妙手采集类API接口

    电商平台趋势,平台化.大家可以看到大的电商都开始有自己的平台,其实这个道理很清楚,就是因为这是充分利用自己的流量.自己的商品和服务大效益化的一个过程,因为有平台,可以利用全社会的资源弥补自己商品的丰富 ...

  4. dfs实现

    1.思路:从图中的未访问的一个顶点开始,沿着一条路一直走到底,然后这条路尽头的节点,在从另外一条路走到底,不断递归此过程,直到所有遍历完成特点:不撞南墙不回头2.具体实现:当从一个未知的顶点出发,将这 ...

  5. Redis 数据类型 Zset

    Redis 数据类型 Zset(有序集合) Redis 常用命令,思维导图 >>> zset是Redis提供的一个非常特别的数据结构,常用作排行榜等功能,以用户id为value,关注 ...

  6. Hugging News #0414: Attention 在多模态情景中的应用、Unity API 以及 Gradio 主题构建器

    每一周,我们的同事都会向社区的成员们发布一些关于 Hugging Face 相关的更新,包括我们的产品和平台更新.社区活动.学习资源和内容更新.开源库和模型更新等,我们将其称之为「Hugging Ne ...

  7. PWN 学习日志(1): pwntools简单使用与栈溢出实践

    常用的模块 模块 功能 asm 汇编与反汇编 dynelf 远程符号泄漏 elf 对elf文件进行操作 memleak 用于内存泄漏 shellcraft shellcode生成器 gdb 配合gdb ...

  8. MAPPO学习笔记(2) —— 从MAPPO论文入手

    在有了上一节一些有关PPO算法的概念作为基础后,我们就可以正式开始对于MAPPO这一算法的学习. 那么,既然要学习一个算法,就不得不去阅读提出这一算法的论文.那么本篇博客将从MAPPO的论文出发,对M ...

  9. MySQL概述与安装

    MySQL数据库 概要: 一.MySQL数据库的概述 二.MySQL数据库的搭建 三.MySQL数据库软件的使用 四.MySQL数据类型 五.MySQL数据库数据的操作 一.初始MySQL数据库 1. ...

  10. lombok版本报错问题java.lang.IllegalAccessError: class lombok.javac.apt.LombokProcessor (in unnamed module

    lombok版本报错问题 记录一个项目部署时遇到的问题,我本地采用的JDK8的版本,然后我的服务器采用的是JDK17,然后在用maven进行打包的时候,发现package失败. 复现 我在本地采用的l ...