在上一篇 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. GitHub+Typora实现云笔记一键上传

    git实现笔记自动上传功能 简介: 将更新内容自动上传同步git,无需手动提交,解锁一键式同步.流程大致为,创建新仓库,配置公钥和私钥,安装quicker软件,通过quicker上某脚本完成一键提交. ...

  2. freeswitch媒体协商的优先级方案

    概述 freeswitch是一款简单好用的VOIP开源软交换平台. 不同的媒体格式各有优缺点,实际环境中的应用要根据线路和客户的实际需求确定. 本文中介绍一种较为通用的媒体配置方案,可以适配大部分场景 ...

  3. c++实战开发程序

    非常感谢您的进一步提问,以下是一个对于实战开发小程序的更具体的建议: 第1周实战开发小程序建议:写一个简单的计算器程序,要求包含加.减.乘.除四种基本运算,并进行错误处理,例如输入了非法字符或者除数为 ...

  4. window远程桌面之通过修改端口链接

      windows开启及连接远程桌面 技术标签: 后端开发  windows         桌面 -> 此电脑 图标右键 -> 属性 远程设置 远程桌面 -> 修改为允许远程连接到 ...

  5. [Linux]VMware启动CENOTS7时报"welcome to emergency mode!"【转载】

    1 问题描述 由于通过VMwaer快速克隆了一台CENTOS7.9的虚拟机. 但启动时报如下错误信息 welcome to emergency mode!after logging in ,type ...

  6. LeeCode 713 乘积小于k的子数组

    LeeCode 713 题目描述: 给你一个整数数组 nums 和一个整数 k ,请你返回子数组内所有元素的乘积严格小于 k 的连续子数组的数目. 标签: 双指针.滑动窗口 建立模型 枚举子数组的右端 ...

  7. day29:计算机网络概念

    目录 1.网络开发的两大架构 2.网络概念 3.OSI七层模型 4.ARP协议 5.TCP三次握手和四次挥手 1.网络开发的两大架构 1.没有网络的时候,文件是如何传输的? 早期没有网络 a.py - ...

  8. 用Abp实现两步验证(Two-Factor Authentication,2FA)登录(三):免登录验证

    @ 目录 原理 修改请求报文 配置JwtBearerOptions 生成Token 校验Token 修改认证EndPoint 修改前端 登录 登出 最终效果 项目地址 免登录验证是用户在首次两步验证通 ...

  9. linux shell 自动化部署 npm vue 项目

    此 shell 是提供给前端登录服务器自动化部署 vue 项目的 用此命令,工具化部署项目,可以杜绝前端自己部署项目时,对服务器违规操作 如有其它问题,可在下方留言! #!/bin/sh # url: ...

  10. 我的OpenAI库发布了!!!

    chatGPT正式发布已经有段时间了,这段时间我也深度体验了chatGPT的魅力. OpenAI除了提供网页版的chatGPT,还通过api的形式提供了很多其它服务,包括文字纠错.图片生成.音频转换等 ...