【Rust 基础篇】Rust类函数宏:代码生成的魔法
导言
Rust是一门现代的、安全的系统级编程语言,它提供了丰富的元编程特性,其中类函数宏(Function-Like Macros)是其中之一。类函数宏允许开发者创建类似函数调用的宏,并在编译期间对代码进行生成和转换。在本篇博客中,我们将深入探讨Rust中的类函数宏,包括类函数宏的定义、使用方法以及一些实际应用案例,以帮助读者充分了解类函数宏的魅力。
1. 类函数宏的基本概念
1.1 类函数宏的定义
在Rust中,类函数宏是一种特殊的宏,它允许开发者创建类似函数调用的宏,并在编译期间对代码进行生成和转换。类函数宏使用proc_macro模块中的TokenStream类型来处理输入和输出。类函数宏的定义基本形式如下:
extern crate proc_macro;use proc_macro::TokenStream;#[proc_macro]
pub fn function_macro(input: TokenStream) -> TokenStream {// 宏的处理逻辑// ...
}
在上述例子中,我们使用proc_macro模块中的TokenStream类型定义了一个名为function_macro的类函数宏。宏接受一个TokenStream参数input,表示宏调用的输入。在宏的处理逻辑中,我们可以根据input对代码进行生成和转换,并返回一个TokenStream作为输出。
1.2 类函数宏的特点
类函数宏在Rust中具有以下几个特点:
-
类似函数调用:类函数宏的语法类似于函数调用,它接受输入参数,并根据输入参数对代码进行生成和转换。这使得宏的使用更加直观和方便。
-
编译期间执行:类函数宏在编译期间执行,而不是运行时执行。这意味着宏生成的代码在编译时就已经确定,不会增加运行时的性能开销。
-
代码安全性:类函数宏生成的代码必须是合法的Rust代码,它们受到Rust编译器的类型检查和安全检查。这保证了宏生成的代码不会引入潜在的编译错误和安全漏洞。
2. 类函数宏的使用方法
2.1 简单的类函数宏例子
让我们从一个简单的例子开始,创建一个类函数宏用于打印输出。
use proc_macro::TokenStream;#[proc_macro]
pub fn print_hello(_input: TokenStream) -> TokenStream {let output = "println!(\"Hello, macro!\");";output.parse().unwrap()
}
在上述例子中,我们定义了一个名为print_hello的类函数宏。在宏的处理逻辑中,我们直接生成了一个输出字符串println!("Hello, macro!");,并将其转换为TokenStream返回。
2.2 带参数的类函数宏例子
类函数宏可以带有参数,让我们创建一个带有参数的类函数宏,用于生成不同类型的输出。
use proc_macro::TokenStream;#[proc_macro]
pub fn print_message(input: TokenStream) -> TokenStream {let message = input.to_string();let output = format!("println!(\"{}!\");", message);output.parse().unwrap()
}
在上述例子中,我们定义了一个名为print_message的类函数宏,并使其带有一个参数input,用于指定输出的消息。在宏的处理逻辑中,我们根据参数生成了不同类型的输出,并将其转换为TokenStream返回。
3. 类函数宏的应用案例
3.1 自定义数据结构
类函数宏可以用于定制化地生成自定义数据结构。让我们通过一个例子来演示如何使用类函数宏生成一个自定义的数据结构。
use proc_macro::TokenStream;#[proc_macro]
pub fn my_struct(input: TokenStream) -> TokenStream {let struct_name = input.to_string();let output = format!("struct {} {{ data: i32 }}", struct_name);output.parse().unwrap()
}
在上述例子中,我们定义了一个名为my_struct的类函数宏,并使其带有一个参数input,用于指定生成的数据结构名。在宏的处理逻辑中,我们根据参数生成了一个自定义的数据结构,并将其转换为TokenStream返回。
3.2 代码块生成
类函数宏还可以用于生成代码块,让我们通过一个例子来演示如何使用类函数宏生成代码块。
use proc_macro::TokenStream;#[proc_macro]
pub fn my_code_block(_input: TokenStream) -> TokenStream {let output = "let x = 10;let y = 20;let sum = x + y;println!(\"Sum: {}\", sum);";output.parse().unwrap()
}
在上述例子中,我们定义了一个名为my_code_block的类函数宏。在宏的处理逻辑中,我们生成了一个代码块,其中包含了一些简单的变量声明和计算,并输出结果。
4. 类函数宏的局限性
虽然类函数宏在Rust中非常强大,但它也有一些局限性需要注意:
-
输入参数的限制:类函数宏的输入参数必须是
TokenStream类型,这限制了宏接受输入参数的种类。在某些情况下,这可能会导致输入参数的处理较长。 -
代码可读性:由于类函数宏生成的代码在宏定义中是以字符串形式存在的,因此在生成复杂的代码时,可读性可能会下降。在使用类函数宏时,需要注意代码生成的可读性和维护性。
-
宏展开的过程:类函数宏的展开过程是在编译期间进行的,这意味着宏展开的过程对于开发者来说是不可见的。在调试宏相关的问题时,可能会增加一些困难。
结论
本篇博客中,我们深入探讨了Rust中的类函数宏,包括其定义、使用方法以及应用案例。类函数宏是Rust中强大且灵活的代码生成工具,它们可以帮助开发者减少代码重复、提高代码的可读性和可维护性,并在编译期间执行,保证了生成的代码的类型安全性。然而,类函数宏也有其局限性,需要开发者根据实际情况进行权衡和使用。
总的来说,Rust的类函数宏是一种非常强大的元编程特性,它为开发者提供了丰富的代码生成和转换能力,可以帮助我们编写更加灵活、简洁和高效的代码。在实际开发中,合理利用类函数宏将会为我们带来更多便利和创新的可能性。
相关文章:
【Rust 基础篇】Rust类函数宏:代码生成的魔法
导言 Rust是一门现代的、安全的系统级编程语言,它提供了丰富的元编程特性,其中类函数宏(Function-Like Macros)是其中之一。类函数宏允许开发者创建类似函数调用的宏,并在编译期间对代码进行生成和转换。在本篇博客中…...
Spring-1-透彻理解Spring XML的Bean创建--IOC
学习目标 上一篇文章我们介绍了什么是Spring,以及Spring的一些核心概念,并且快速快发一个Spring项目,实现IOC和DI,今天具体来讲解IOC 能够说出IOC的基础配置和Bean作用域 了解Bean的生命周期 能够说出Bean的实例化方式 一、Bean的基础配置 …...
【JAVA】类和对象
作者主页:paper jie的博客 本文作者:大家好,我是paper jie,感谢你阅读本文,欢迎一建三连哦。 本文录入于《JAVASE语法系列》专栏,本专栏是针对于大学生,编程小白精心打造的。笔者用重金(时间和精…...
jenkins准备
回到目录 jenkins是一个开源的、提供友好操作界面的持续集成(CI)工具,主要用于持续、自动的构建/测试软件项目、监控外部任务的运行。Jenkins用Java语言编写,可在Tomcat等流行的servlet容器中运行,也可独立运行。通常与版本管理工具(SCM)、构…...
【Rust】Rust学习
文档:Rust 程序设计语言 - Rust 程序设计语言 简体中文版 (bootcss.com) 墙裂推荐这个文档 第一章入门 入门指南 - Rust 程序设计语言 简体中文版 第二章猜猜看游戏 猜猜看游戏教程 - Rust 程序设计语言 简体中文版 (bootcss.com) // 导入库 use std::io; use s…...
Linux 常用命令之配置环境变量 PATH
PATH是系统环境变量中的一种,同时将一些二进制文件的绝对路径追加进去,则在系统终端中可以发现这些路径下的文件。 一. 环境变量设置 export PATH<二进制文件的绝对路径>:$PATH 以下为结合实际例子的操作 1、临时设置 打开一个终端执行如下命令 e…...
flask-----蓝图
1.引入蓝图 flask都写在一个文件中,项目这样肯定不行,会导致循环导入的问题,分目录,分包,使用蓝图划分目录。 2.使用蓝图 步骤如下: -1 实例化得到一个蓝图对象-order_blueBlueprint(order,__name__,tem…...
学习左耳听风栏目90天——第一天 1-90(学习左耳朵耗子的工匠精神,对技术的热爱)【洞悉技术的本质,享受科技的乐趣】
洞悉技术的本质,享受科技的乐趣 第一篇,我的感受就是 耗叔是一个热爱技术,可以通过代码找到快乐的技术人。 作为it从业者,我们如何可以通过代码找到快乐呢?这是一个问题? 至少目前,我还没有这种…...
后端登录安全的一种思路
PS:作者是小白能接触到的就只会这样写。勿喷。 前提 思路: 结合io流将登录token存储到配置文件中,不将token存储到浏览器端,从而避免盗取。 下面jwt的学习可以参考下这个: JWT --- 入门学习_本郡主是喵的博客-CSDN博客 JWT工具类 Component public class JWTtU…...
【深度学习_TensorFlow】激活函数
写在前面 上篇文章我们了解到感知机使用的阶跃函数和符号函数,它们都是非连续,导数为0的函数: 建议回顾上篇文章,本篇文章将介绍神经网络中的常见激活函数,这些函数都是平滑可导的,适合于梯度下降算法。 写…...
机器学习笔记之优化算法(七)线搜索方法(步长角度;非精确搜索;Wolfe Condition)
机器学习笔记之优化算法——线搜索方法[步长角度,非精确搜索,Wolfe Condition] 引言回顾: Armijo \text{Armijo} Armijo准则及其弊端 Glodstein \text{Glodstein} Glodstein准则及其弊端 Wolfe Condition \text{Wolfe Condition} Wolfe Condi…...
十四.redis哨兵模式
redis哨兵模式 1.概述2.测试3.哨兵模式优缺点 redis哨兵模式基础是主从复制 1.概述 主从切换的技术方法:当主节点服务器宕机后,需要手动把一台从服务器切换为主服务器,这就需要人工干预,费时费力,还会造成一段时间内服…...
采用UWB技术开发的智慧工厂人员定位系统源码【UWB定位基站、卡牌】
UWB (ULTRA WIDE BAND, UWB) 技术是一种无线载波通讯技术,它不采用正弦载波,而是利用纳秒级的非正弦波窄脉冲传输数据,因此其所占的频谱范围很宽。UWB定位系统依托在移动通信,雷达,微波电路,云计算与大数据…...
当你软件测试遇上加密接口,是不是就不能测了?
相信大家在工作中做接口测试的时候,肯定会遇到一个场景,那就是你们的软件,密码是加密存储的。 那么这样的话,我们在执行接口的时候,对于密码的处理就开始头疼了。 所以,本文将使用jmeter这款java开源的接…...
Flink
Flink(Apache Flink)是一个开源的分布式流处理引擎和批处理框架。它是由 Apache 软件基金会维护的项目,旨在处理大规模数据的实时流式处理和批处理任务。Flink 提供了强大的流处理和批处理功能,具有低延迟、高吞吐量和高容错性&am…...
python入门常用操作
python常用操作 1、ndarry数组的切片2、print用法2.1格式化输出format2.2字符串格式化输出 3、均值滤波函数 1、ndarry数组的切片 例如一个5列的ndarry数组,想要获取第2列和第3列数据,可以用 #(1)用法1 data[:,1:3],…...
SpringBoot复习:(21)自定义ImportBeanDefinitionRegistrar
要达到的目的:将某个包下使用了某个自定义注解(比如MyClassMapper)的类注册到Spring 容器。 一、自定义注解: package com.example.demo.service;import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy;Rete…...
小黑子—JavaWeb:第五章 - JSP与会话跟踪技术
JavaWeb入门5.0 1. JSP1.1 JSP快速入门1.2 JSP原理1.3 JSP脚本1.3.1 JSP缺点 1.4 EL 表达式1.5 JSTL 标签1.5.1 JSTL 快速入门1.5.1 - I JSTL标签if1.5.1 - II JSTL标签forEach 1.6 MVC模式1.7 三层架构1.8 实现案例1.8.1 环境准备1.8.2 查询所有1.8.3 添加数据1.8.4 修改1.8.4…...
Python - 【socket】 客户端client重连处理简单示例Demo(一)
一. 前言 在Python中,使用socket进行网络通信时,如果连接断开,可以通过以下步骤实现重连处理 二. 示例代码 1. 定义一个函数,用于建立socket连接 import socketdef connect_socket(host, port):while True:try:# 建立socket连…...
Redis 基础
1.定义 Redis 是一个高性能的key-value数据库,key是字符串类型。 2.核心特点: 单进程: Redis的服务器程序采用的是单进程模型来处理客户端的请求。对读写时间的响 应是通过对epoll函数的包装来做到的。 3.数据类型: 键的类型…...
安宝特方案丨XRSOP人员作业标准化管理平台:AR智慧点检验收套件
在选煤厂、化工厂、钢铁厂等过程生产型企业,其生产设备的运行效率和非计划停机对工业制造效益有较大影响。 随着企业自动化和智能化建设的推进,需提前预防假检、错检、漏检,推动智慧生产运维系统数据的流动和现场赋能应用。同时,…...
【Web 进阶篇】优雅的接口设计:统一响应、全局异常处理与参数校验
系列回顾: 在上一篇中,我们成功地为应用集成了数据库,并使用 Spring Data JPA 实现了基本的 CRUD API。我们的应用现在能“记忆”数据了!但是,如果你仔细审视那些 API,会发现它们还很“粗糙”:有…...
爬虫基础学习day2
# 爬虫设计领域 工商:企查查、天眼查短视频:抖音、快手、西瓜 ---> 飞瓜电商:京东、淘宝、聚美优品、亚马逊 ---> 分析店铺经营决策标题、排名航空:抓取所有航空公司价格 ---> 去哪儿自媒体:采集自媒体数据进…...
自然语言处理——循环神经网络
自然语言处理——循环神经网络 循环神经网络应用到基于机器学习的自然语言处理任务序列到类别同步的序列到序列模式异步的序列到序列模式 参数学习和长程依赖问题基于门控的循环神经网络门控循环单元(GRU)长短期记忆神经网络(LSTM)…...
10-Oracle 23 ai Vector Search 概述和参数
一、Oracle AI Vector Search 概述 企业和个人都在尝试各种AI,使用客户端或是内部自己搭建集成大模型的终端,加速与大型语言模型(LLM)的结合,同时使用检索增强生成(Retrieval Augmented Generation &#…...
AGain DB和倍数增益的关系
我在设置一款索尼CMOS芯片时,Again增益0db变化为6DB,画面的变化只有2倍DN的增益,比如10变为20。 这与dB和线性增益的关系以及传感器处理流程有关。以下是具体原因分析: 1. dB与线性增益的换算关系 6dB对应的理论线性增益应为&…...
深度学习水论文:mamba+图像增强
🧀当前视觉领域对高效长序列建模需求激增,对Mamba图像增强这方向的研究自然也逐渐火热。原因在于其高效长程建模,以及动态计算优势,在图像质量提升和细节恢复方面有难以替代的作用。 🧀因此短时间内,就有不…...
现有的 Redis 分布式锁库(如 Redisson)提供了哪些便利?
现有的 Redis 分布式锁库(如 Redisson)相比于开发者自己基于 Redis 命令(如 SETNX, EXPIRE, DEL)手动实现分布式锁,提供了巨大的便利性和健壮性。主要体现在以下几个方面: 原子性保证 (Atomicity)ÿ…...
宇树科技,改名了!
提到国内具身智能和机器人领域的代表企业,那宇树科技(Unitree)必须名列其榜。 最近,宇树科技的一项新变动消息在业界引发了不少关注和讨论,即: 宇树向其合作伙伴发布了一封公司名称变更函称,因…...
省略号和可变参数模板
本文主要介绍如何展开可变参数的参数包 1.C语言的va_list展开可变参数 #include <iostream> #include <cstdarg>void printNumbers(int count, ...) {// 声明va_list类型的变量va_list args;// 使用va_start将可变参数写入变量argsva_start(args, count);for (in…...
