用声明式宏解析 Rust 语法
在上一篇 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 语法的更多相关文章
- DEVOPS技术实践_08:声明式管道语法
简介 前面简单的做了管道的实验,看了一下的它的效果 声明式管道是Groovy语法中的一个更简单和结构化的语法.下面主要学习明式管道语法. 一 声明式管道的基本结构 以上节的代码为例 node { de ...
- Jenkins教程——从安装到部署Docker服务(二)声明式流水线HelloWorld
前言 本文通过一个声明式流水线的HelloWorld程序做一下流水线基础入门,对常用的流水线参数进行简要说明 什么是流水线 现实中的流水线 流水线比较好理解,类比于现实生活中的生产流水线,每个流程只做 ...
- 【Kubernetes】深入解析声明式API
在Kubernetes中,一个API对象在Etcd里的完整资源路径,是由:Group(API组).Version(API版本)和Resource(API资源类型)三个部分组成的. 通过这样的结构,整个 ...
- Jenkins pipeline声明式语法
目录 一.最简结构 二.简单例子 一.最简结构 pipeline { agent any stages { stage('pull') { st ...
- spring声明式事务管理详情解析
前沿:通过对spring事务管理有了比较深入学习,本文将不做实例,而是指定具体的类和配置文件进行讲解. 本文内容: 1.了解什么是声明式事务? 2.声明式事务管理分别有哪几种? 3.这几种事务管理之间 ...
- spring5 源码深度解析----- @Transactional注解的声明式事物介绍(100%理解事务)
面的几个章节已经分析了spring基于@AspectJ的源码,那么接下来我们分析一下Aop的另一个重要功能,事物管理. 事务的介绍 1.数据库事物特性 原子性多个数据库操作是不可分割的,只有所有的操作 ...
- spring cloud深入学习(四)-----eureka源码解析、ribbon解析、声明式调用feign
基本概念 1.Registe 一一服务注册当eureka Client向Eureka Server注册时,Eureka Client提供自身的元数据,比如IP地址.端口.运行状况指标的Uri.主页地址 ...
- How Javascript works (Javascript工作原理) (十四) 解析,语法抽象树及最小化解析时间的 5 条小技巧
个人总结:读完这篇文章需要15分钟,文章介绍了抽象语法树与js引擎解析这些语法树的过程,提到了懒解析——即转换为AST的过程中不直接进入函数体解析,当这个函数体需要执行的时候才进行相应转换.(因为有的 ...
- JavaScript在页面中的执行顺序(理解声明式函数与赋值式函数) 转载
JavaScript在页面中的执行顺序 https://blog.csdn.net/superhoy/article/details/52946277 2016年10月27日 15:38:52 阅读数 ...
- 关于CSS自文档的思考_css声明式语言式代码注释
obert C. Martin写的<Clean Code>是我读过的最好的编程书籍之一,若没有读过,推荐你将它加入书单. 注释就意味着代码无法自说明 —— Robert C. Martin ...
随机推荐
- PVE Cloud-INIT 模板配置
PVE Cloud-INIT 模板配置 Cloud-init是什么 Cloud-init是开源的云初始化程序,能够对新创建弹性云服务器中指定的自定义信息(主机名.密钥和用户数据等)进行初始化配置.通过 ...
- 使用frp进行内网穿透
frp 是一个专注于内网穿透的高性能的反向代理应用,支持 TCP.UDP.HTTP.HTTPS 等多种协议.可以将内网服务以安全.便捷的方式通过具有公网 IP 节点的中转暴露到公网. frp is a ...
- 安装部署keepalived的HA环境
每一台配置下keepalived #master01 配置: cat >/etc/keepalived/keepalived.conf<<"EOF" ! Conf ...
- Nordic nRF52系列/nRF5340硬件设计(一)选型及原理图设计
Nordic 的BLE系列芯片从第一代的nRF51系列,到第二代的nRF52系列,发展到目前最新的第三代的nRF5340.目前市场中使用最多的nRF52系列一共有七款芯片,它们是:nRF52805.n ...
- 【AIGC未来的发展方向】面向人工智能的第一步,一文告诉你人工智能是什么以及未来的方向分析
人工智能的概念 当人们提到"人工智能(AI)"时,很多人会想到机器人和未来世界的科幻场景,但AI的应用远远不止于此.现在,AI已经广泛应用于各种行业和生活领域,为我们带来了无限可能 ...
- Ficow 的 AI 平台快速上手指南(ChatGPT, NewBing, ChatGLM-6B, cursor.so)
本文首发于 Ficow Shen's Blog,原文地址: Ficow 的 AI 平台快速上手指南(ChatGPT, NewBing, ChatGLM-6B, cursor.so). 内容概览 前言 ...
- 碉堡!“万物皆可分”标记模型上线「GitHub 热点速览」
这周有个让人眼前一亮的图像识别模型 segment-anything,它能精细地框出所有可见物体,它标记出的物体边界线清晰可见.如此出色的模型,自然获得了不少人的赞赏,开源没几天,就拿下了 18k+ ...
- 为什么一定要用Redis?
参考: 为什么分布式一定要有Redis? 选redis还是memcache,源码怎么说?
- Python程序笔记20230306
判断闰年 初始版本 year = input('请输入一个年份:') while not year.isdigit(): year = input("抱歉,您的输入有误,请输入一个整数:&q ...
- Solidity 入门
基本语法 版本指令 所有Solidity源码都必须指明版本,用于标明Solidity编译器的版本,这是为了避免将来新的编译器破坏代码 pragma solidity ^0.4.20; // 声明版本 ...