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,缓存的网络图像的存储和检索用…...
[特殊字符] 智能合约中的数据是如何在区块链中保持一致的?
🧠 智能合约中的数据是如何在区块链中保持一致的? 为什么所有区块链节点都能得出相同结果?合约调用这么复杂,状态真能保持一致吗?本篇带你从底层视角理解“状态一致性”的真相。 一、智能合约的数据存储在哪里…...
React 第五十五节 Router 中 useAsyncError的使用详解
前言 useAsyncError 是 React Router v6.4 引入的一个钩子,用于处理异步操作(如数据加载)中的错误。下面我将详细解释其用途并提供代码示例。 一、useAsyncError 用途 处理异步错误:捕获在 loader 或 action 中发生的异步错误替…...
shell脚本--常见案例
1、自动备份文件或目录 2、批量重命名文件 3、查找并删除指定名称的文件: 4、批量删除文件 5、查找并替换文件内容 6、批量创建文件 7、创建文件夹并移动文件 8、在文件夹中查找文件...
CocosCreator 之 JavaScript/TypeScript和Java的相互交互
引擎版本: 3.8.1 语言: JavaScript/TypeScript、C、Java 环境:Window 参考:Java原生反射机制 您好,我是鹤九日! 回顾 在上篇文章中:CocosCreator Android项目接入UnityAds 广告SDK。 我们简单讲…...
EtherNet/IP转DeviceNet协议网关详解
一,设备主要功能 疆鸿智能JH-DVN-EIP本产品是自主研发的一款EtherNet/IP从站功能的通讯网关。该产品主要功能是连接DeviceNet总线和EtherNet/IP网络,本网关连接到EtherNet/IP总线中做为从站使用,连接到DeviceNet总线中做为从站使用。 在自动…...
第 86 场周赛:矩阵中的幻方、钥匙和房间、将数组拆分成斐波那契序列、猜猜这个单词
Q1、[中等] 矩阵中的幻方 1、题目描述 3 x 3 的幻方是一个填充有 从 1 到 9 的不同数字的 3 x 3 矩阵,其中每行,每列以及两条对角线上的各数之和都相等。 给定一个由整数组成的row x col 的 grid,其中有多少个 3 3 的 “幻方” 子矩阵&am…...
三分算法与DeepSeek辅助证明是单峰函数
前置 单峰函数有唯一的最大值,最大值左侧的数值严格单调递增,最大值右侧的数值严格单调递减。 单谷函数有唯一的最小值,最小值左侧的数值严格单调递减,最小值右侧的数值严格单调递增。 三分的本质 三分和二分一样都是通过不断缩…...
[论文阅读]TrustRAG: Enhancing Robustness and Trustworthiness in RAG
TrustRAG: Enhancing Robustness and Trustworthiness in RAG [2501.00879] TrustRAG: Enhancing Robustness and Trustworthiness in Retrieval-Augmented Generation 代码:HuichiZhou/TrustRAG: Code for "TrustRAG: Enhancing Robustness and Trustworthin…...
消息队列系统设计与实践全解析
文章目录 🚀 消息队列系统设计与实践全解析🔍 一、消息队列选型1.1 业务场景匹配矩阵1.2 吞吐量/延迟/可靠性权衡💡 权衡决策框架 1.3 运维复杂度评估🔧 运维成本降低策略 🏗️ 二、典型架构设计2.1 分布式事务最终一致…...
es6+和css3新增的特性有哪些
一:ECMAScript 新特性(ES6) ES6 (2015) - 革命性更新 1,记住的方法,从一个方法里面用到了哪些技术 1,let /const块级作用域声明2,**默认参数**:函数参数可以设置默认值。3&#x…...
