Rust derive macro(Rust #[derive])Rust派生宏
参考文章:附录 D:派生特征 trait
文章目录
- Rust 中的派生宏 #[derive]
- 基础使用
- 示例:派生 `Debug`
- 派生其他常用特征
- 示例:派生 `Clone` 和 `Copy`
- 派生宏的限制和自定义派生
- 自定义派生宏
- 上面代码运行时报错了,以下是解释
- 结论
Rust 中的派生宏 #[derive]
在 Rust 中,派生宏(derive macro)是一种自动实现特定特征(trait)的工具,极大地简化了代码的编写和维护过程。通过使用 #[derive] 属性,开发者可以轻松为自定义数据类型实现一系列的标准特征,例如 Debug、Clone、Copy、Hash、PartialEq 和 Eq 等。本文将深入探讨派生宏的工作原理、使用方式以及如何自定义派生宏。
基础使用
派生宏最常见的应用是自动实现标准库中的特征。例如,当你需要打印一个结构体的调试信息时,可以派生 Debug 特征。
示例:派生 Debug
#![allow(dead_code)] // 忽略全局dead code,放在模块开头!
#![allow(unused_variables)] // 忽略未使用变量,放在模块开头!#[derive(Debug)]struct Point {x: i32,y: i32,
}fn main() {let point = Point { x: 10, y: 20 };println!("{:?}", point); // 使用 Debug 特征打印 point
}

在上述代码中,#[derive(Debug)] 使得 Point 结构体自动实现了 Debug 特征,允许我们通过 println! 宏以调试格式打印结构体的实例。
派生其他常用特征
除了 Debug,Rust 还允许自动派生其他一些重要的特征。
示例:派生 Clone 和 Copy
#![allow(dead_code)] // 忽略全局dead code,放在模块开头!
#![allow(unused_variables)] // 忽略未使用变量,放在模块开头!#[derive(Debug, Clone, Copy)]struct Point {x: i32,y: i32,
}fn main() {let point1 = Point { x: 10, y: 20 };let point2 = point1; // Copy 特性允许这样的操作let point3 = point1.clone(); // Clone 特性的显式调用println!("{:?}", point2); // 使用 Debug 特征打印 point2println!("{:?}", point3); // 使用 Debug 特征打印 point3
}

在此示例中,Point 结构体通过 #[derive] 同时实现了 Debug、Clone 和 Copy 特征。Copy 是用于简单字段复制的轻量级特征,而 Clone 用于可能涉及到更复杂的数据克隆过程。
派生宏的限制和自定义派生
尽管派生宏非常有用,但它们并不适用于所有情况。例如,当结构体的某些字段不支持相应的特征时,直接使用派生宏可能会导致编译错误。
自定义派生宏
对于标准特征之外的特定用途,或当内置的派生无法满足需求时,Rust 允许创建自定义派生宏。自定义派生宏需要深入了解 Rust 的宏系统和特征实现。
use proc_macro::TokenStream;
use quote::quote;
use syn::{parse_macro_input, DeriveInput};#[proc_macro_derive(MyTrait)]
pub fn my_trait_derive(input: TokenStream) -> TokenStream {let input = parse_macro_input!(input as DeriveInput);let name = &input.ident;let expanded = quote! {impl MyTrait for #name {fn my_trait_method(&self) -> String {format!("This is a MyTrait method implemented for {}", stringify!(#name))}}};TokenStream::from(expanded)
}
在上述示例中,定义了一个新的派生宏 MyTrait,它为指定的数据类型实现了 MyTrait 特征,包括一个方法 my_trait_method。使用 proc_macro 创建派生宏涉及解析类型定义、生成相应的代码,并将其输出为令牌流,这是 Rust 宏系统的核心。
上面代码运行时报错了,以下是解释
在 Rust 中,#[proc_macro_derive] 属性只能在 proc-macro 类型的 crate 中使用。这意味着你需要将你的代码放在一个特别设定为 proc-macro 类型的库中才能编译和运行。以下是设置步骤:
-
创建新的 proc-macro crate:
- 通常,你需要创建一个新的库专门用来编写 proc macro。你可以使用
cargo new --lib my_proc_macro命令来创建一个新的库。确保你在创建时的目录不在其他项目中。
- 通常,你需要创建一个新的库专门用来编写 proc macro。你可以使用
-
修改 Cargo.toml:
- 在你的
Cargo.toml文件中,你需要指定库的类型为proc-macro。这可以通过添加proc-macro = true到[lib]部分实现:[lib] proc-macro = true
- 在你的
-
将代码移动到新的 crate:
- 把你的 proc macro 代码复制到新创建的库的
src/lib.rs文件中。
- 把你的 proc macro 代码复制到新创建的库的
-
添加依赖:
- 你需要在
Cargo.toml中添加proc_macro,quote, 和syn作为依赖项。这样你的代码才能编译。[dependencies] quote = "1.0" syn = { version = "1.0", features = ["full"] }
- 你需要在
-
编译并使用你的 proc-macro crate:
- 在你的主项目中,添加对你刚创建的 proc-macro 库的依赖。这通常通过在主项目的
Cargo.toml中添加路径依赖来实现:[dependencies] my_proc_macro = { path = "../path_to_my_proc_macro" }
- 在你的主项目中,添加对你刚创建的 proc-macro 库的依赖。这通常通过在主项目的
-
使用 proc-macro:
- 现在,你可以在你的主项目中通过使用
#[derive(MyTrait)]来使用你的 proc macro。
- 现在,你可以在你的主项目中通过使用
确保你的目录结构和依赖管理都设置正确,这样你就可以成功地编译和使用你的 proc macro。如果你需要进一步的帮助,可以随时提问!
结论
Rust 的 #[derive] 宏提供了一种高效的方式来自动实现多种特征,从而减少重复代码并提升开发效率。通过自定义派生宏,开发者还可以扩展这一机制以适应更广泛的应用场景。
相关文章:
Rust derive macro(Rust #[derive])Rust派生宏
参考文章:附录 D:派生特征 trait 文章目录 Rust 中的派生宏 #[derive]基础使用示例:派生 Debug 派生其他常用特征示例:派生 Clone 和 Copy 派生宏的限制和自定义派生自定义派生宏上面代码运行时报错了,以下是解释 结论…...
springboot嗨玩旅游网站
摘 要 嗨玩旅游网站是一个专为旅行爱好者打造的在线平台。我们提供丰富多样的旅游目的地信息,包括景点信息、旅游线路、商品信息、社区信息、活动推广等,帮助用户轻松规划行程。嗨玩旅游网站致力于为用户提供便捷、实用的旅行服务,让每一次旅…...
杰发科技AC7840——EEP中RAM的配置
sample和手册中示例代码的sram区地址定义不一样 这个在RAM中使用没有限制,根据这个表格留下足够空间即可 比如需要4096字节的eep空间,可以把RAM的地址改成E000,即E000-EFFF,共4096bytes即可。...
从零开始的c++之旅——map_set的使用
1.序列式容器和关联式容器 序列式容器:逻辑结构为线性序列的数据结构,两个位置之间没有紧密的关系,比如两者交换一下还是序列式的容器,例如string,vector,deque,array等。 关联式容器࿱…...
Docker中的一些常用命令
find / -type f -name “文件名” 2>/dev/null 寻找所有目录中的这个文件 pwd 查看当前目录的地址 docker pull 镜像名 强制拉镜像 docker run 运行docker systemctl daemon-reload 关闭docker systemctl start docker 启动docker systemctl restart docker 重启docker /…...
自存 sql常见语句和实际应用
关于连表 查询两个表 SELECT * FROM study_article JOIN study_article_review 查询的就是两个表相乘,结果为两个表的笛卡尔积 相这样 这种并不是我们想要的结果 通常会添加一些查询条件 SELECT * FROM study_articleJOIN study_article_review ON study_art…...
python | argparse模块在命令行的使用中的重要作用
import argparseclass TestCases:def __init__(self, nameNone, expect_resultNone):self.name nameself.expect expect_resultself.parser argparse.ArgumentParser() # 创建命令解析器self.add_arguments() # 方法 : 添加命令self.args, _ self.parser.par…...
【HCIP]——OSPF综合实验
题目 实验需求 根据上图可得,实验需求为: 1.R5作为ISP:其上只能配置IP地址;R4作为企业边界路由器,出口公网地址需要通过PPP协议获取,并进行CHAP认证。(PS:因PPP协议尚未学习&#…...
PW系列工控电脑复制机:效率与精度双重提升
工控电脑复制应用:效率与精度的双重提升 随着现代企业对大数据、数据备份、和跨平台兼容性需求的快速增长,工控电脑已成为数据密集型产业的核心设备。针对工控环境中大量数据复制的特殊需求,PW系列NVMe/SATA PCIe SSD复制机(如PW…...
学习QT第二天
QT6示例运行 运行一个Widgets程序运行一个QT Quick示例 工作太忙了,难得抽空学点东西。-_-||| 博客中有错误的地方,请各位道友及时指正,感谢! 运行一个Widgets程序 在QT Creator的欢迎界面中,点击左侧的示例…...
11.20作业
题目一: 题目: // 数组的行列转置 代码: // 数组的行列转置 #include <stdio.h> int main() {int a[2][3], i, j, b[3][2];printf("输入一个两行三列的数组a:\n");for (i 0; i < 2; i)for (j 0; j < 3; j){scanf…...
Ubuntu Linux使用前准备动作_使用root登录图形化界面
Ubuntu默认是不允许使用 root 登录图形化界面的。这是出于安全考虑的设置。但如果有需要,可以通过以下步骤来实现使用 root 登录: 1、设置 root 密码 打开终端,使用当前的管理员账户登录系统。在终端中输入命令sudo passwd root,…...
DICOM核心概念:显式 VR(Explicit VR)与隐式 VR(Implicit VR)在DICOM中的定义与区别
在DICOM(Digital Imaging and Communications in Medicine)标准中,VR(Value Representation) 表示数据元素的值的类型和格式。理解显式 VR(Explicit VR)与隐式 VR(Implicit VR&#…...
源码分析Spring Boot (v3.3.0)
. ____ _ __ _ _/\\ / ____ __ _ _(_)_ __ __ _ \ \ \ \ ( ( )\___ | _ | _| | _ \/ _ | \ \ \ \\\/ ___)| |_)| | | | | || (_| | ) ) ) ) |____| .__|_| |_|_| |_\__, | / / / /|_||___//_/_/_/:: Spring Boot :: (v3.3.0)//笔记背…...
IPv6 NDP 记录
NDP(Neighbor Discovery Protocol,邻居发现协议) 是 IPv6 的一个关键协议,它组合了 IPv4 中的 ARP、ICMP 路由器发现和 ICMP 重定向等协议,并对它们作出了改进。该协议使用 ICMPv6 协议实现,作为 IPv6 的基…...
linux常用命令(文件操作)
目录 1. ls - 列出目录内容 2. cd - 更改目录 3. pwd - 打印当前工作目录 4. mkdir - 创建目录 5. rm - 删除文件或目录 6. cp - 复制文件或目录 7. mv - 移动或重命名文件 8. touch - 更新文件访问和修改时间 9. cat - 显示文件内容 10. grep - 搜索文本 11. chmod…...
内存管理 I(内存管理的基本原理和要求、连续分配管理方式)
一、内存管理的基本原理和要求 内存管理(Memory Management)是操作系统设计中最重要和最复杂的内容之一。虽然计算机硬件技术一直在飞速发展,内存容量也在不断增大,但仍然不可能将所有用户进程和系统所需要的全部程序与数据放入主…...
【Redis】基于Redis实现秒杀功能
业务的流程大概就是,先判断优惠卷是否过期,然后判断是否有库存,最好进行扣减库存,加入全局唯一id,然后生成订单。 一、超卖问题 真是的场景下可能会有超卖问题,比如开200个线程进行抢购,抢100个…...
Hadoop 使用过程中 15 个常见问题的详细描述、解决方案
目录 问题 1:配置文件路径错误问题描述解决方案Python 实现 问题 2:YARN 资源配置不足问题描述解决方案Python 实现 问题 3:DataNode 无法启动问题描述解决方案Python 实现 问题 4:NameNode 格式化失败问题描述解决方案Python 实现…...
【Flutter 问题系列第 84 篇】如何清除指定网络图片的缓存
这是【Flutter 问题系列第 84 篇】,如果觉得有用的话,欢迎关注专栏。 博文当前所用 Flutter SDK:3.24.3、Dart SDK:3.5.3,网络图片缓存用的插件 cached_network_image: 3.4.1,缓存的网络图像的存储和检索用…...
FFmpeg 低延迟同屏方案
引言 在实时互动需求激增的当下,无论是在线教育中的师生同屏演示、远程办公的屏幕共享协作,还是游戏直播的画面实时传输,低延迟同屏已成为保障用户体验的核心指标。FFmpeg 作为一款功能强大的多媒体框架,凭借其灵活的编解码、数据…...
Cesium1.95中高性能加载1500个点
一、基本方式: 图标使用.png比.svg性能要好 <template><div id"cesiumContainer"></div><div class"toolbar"><button id"resetButton">重新生成点</button><span id"countDisplay&qu…...
线程与协程
1. 线程与协程 1.1. “函数调用级别”的切换、上下文切换 1. 函数调用级别的切换 “函数调用级别的切换”是指:像函数调用/返回一样轻量地完成任务切换。 举例说明: 当你在程序中写一个函数调用: funcA() 然后 funcA 执行完后返回&…...
数据链路层的主要功能是什么
数据链路层(OSI模型第2层)的核心功能是在相邻网络节点(如交换机、主机)间提供可靠的数据帧传输服务,主要职责包括: 🔑 核心功能详解: 帧封装与解封装 封装: 将网络层下发…...
Linux云原生安全:零信任架构与机密计算
Linux云原生安全:零信任架构与机密计算 构建坚不可摧的云原生防御体系 引言:云原生安全的范式革命 随着云原生技术的普及,安全边界正在从传统的网络边界向工作负载内部转移。Gartner预测,到2025年,零信任架构将成为超…...
【配置 YOLOX 用于按目录分类的图片数据集】
现在的图标点选越来越多,如何一步解决,采用 YOLOX 目标检测模式则可以轻松解决 要在 YOLOX 中使用按目录分类的图片数据集(每个目录代表一个类别,目录下是该类别的所有图片),你需要进行以下配置步骤&#x…...
大数据学习(132)-HIve数据分析
🍋🍋大数据学习🍋🍋 🔥系列专栏: 👑哲学语录: 用力所能及,改变世界。 💖如果觉得博主的文章还不错的话,请点赞👍收藏⭐️留言Ǵ…...
视觉slam十四讲实践部分记录——ch2、ch3
ch2 一、使用g++编译.cpp为可执行文件并运行(P30) g++ helloSLAM.cpp ./a.out运行 二、使用cmake编译 mkdir build cd build cmake .. makeCMakeCache.txt 文件仍然指向旧的目录。这表明在源代码目录中可能还存在旧的 CMakeCache.txt 文件,或者在构建过程中仍然引用了旧的路…...
MySQL 知识小结(一)
一、my.cnf配置详解 我们知道安装MySQL有两种方式来安装咱们的MySQL数据库,分别是二进制安装编译数据库或者使用三方yum来进行安装,第三方yum的安装相对于二进制压缩包的安装更快捷,但是文件存放起来数据比较冗余,用二进制能够更好管理咱们M…...
FFmpeg:Windows系统小白安装及其使用
一、安装 1.访问官网 Download FFmpeg 2.点击版本目录 3.选择版本点击安装 注意这里选择的是【release buids】,注意左上角标题 例如我安装在目录 F:\FFmpeg 4.解压 5.添加环境变量 把你解压后的bin目录(即exe所在文件夹)加入系统变量…...
