当前位置: 首页 > news >正文

Rust derive macro(Rust #[derive])Rust派生宏

参考文章:附录 D:派生特征 trait

文章目录

  • Rust 中的派生宏 #[derive]
    • 基础使用
      • 示例:派生 `Debug`
    • 派生其他常用特征
      • 示例:派生 `Clone` 和 `Copy`
    • 派生宏的限制和自定义派生
      • 自定义派生宏
        • 上面代码运行时报错了,以下是解释
    • 结论

Rust 中的派生宏 #[derive]

在 Rust 中,派生宏(derive macro)是一种自动实现特定特征(trait)的工具,极大地简化了代码的编写和维护过程。通过使用 #[derive] 属性,开发者可以轻松为自定义数据类型实现一系列的标准特征,例如 DebugCloneCopyHashPartialEqEq 等。本文将深入探讨派生宏的工作原理、使用方式以及如何自定义派生宏。

基础使用

派生宏最常见的应用是自动实现标准库中的特征。例如,当你需要打印一个结构体的调试信息时,可以派生 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 还允许自动派生其他一些重要的特征。

示例:派生 CloneCopy

#![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] 同时实现了 DebugCloneCopy 特征。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 类型的库中才能编译和运行。以下是设置步骤:

  1. 创建新的 proc-macro crate

    • 通常,你需要创建一个新的库专门用来编写 proc macro。你可以使用 cargo new --lib my_proc_macro 命令来创建一个新的库。确保你在创建时的目录不在其他项目中。
  2. 修改 Cargo.toml

    • 在你的 Cargo.toml 文件中,你需要指定库的类型为 proc-macro。这可以通过添加 proc-macro = true[lib] 部分实现:
      [lib]
      proc-macro = true
      
  3. 将代码移动到新的 crate

    • 把你的 proc macro 代码复制到新创建的库的 src/lib.rs 文件中。
  4. 添加依赖

    • 你需要在 Cargo.toml 中添加 proc_macro, quote, 和 syn 作为依赖项。这样你的代码才能编译。
      [dependencies]
      quote = "1.0"
      syn = { version = "1.0", features = ["full"] }
      
  5. 编译并使用你的 proc-macro crate

    • 在你的主项目中,添加对你刚创建的 proc-macro 库的依赖。这通常通过在主项目的 Cargo.toml 中添加路径依赖来实现:
      [dependencies]
      my_proc_macro = { path = "../path_to_my_proc_macro" }
      
  6. 使用 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等。 关联式容器&#xff1…...

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的欢迎界面中,点击左侧的示例&#xf…...

11.20作业

题目一&#xff1a; 题目&#xff1a; // 数组的行列转置 代码&#xff1a; // 数组的行列转置 #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 登录图形化界面的。这是出于安全考虑的设置。但如果有需要&#xff0c;可以通过以下步骤来实现使用 root 登录&#xff1a; 1、设置 root 密码 打开终端&#xff0c;使用当前的管理员账户登录系统。在终端中输入命令sudo passwd root&#xff0c…...

DICOM核心概念:显式 VR(Explicit VR)与隐式 VR(Implicit VR)在DICOM中的定义与区别

在DICOM&#xff08;Digital Imaging and Communications in Medicine&#xff09;标准中&#xff0c;VR&#xff08;Value Representation&#xff09; 表示数据元素的值的类型和格式。理解显式 VR&#xff08;Explicit VR&#xff09;与隐式 VR&#xff08;Implicit VR&#…...

源码分析Spring Boot (v3.3.0)

. ____ _ __ _ _/\\ / ____ __ _ _(_)_ __ __ _ \ \ \ \ ( ( )\___ | _ | _| | _ \/ _ | \ \ \ \\\/ ___)| |_)| | | | | || (_| | ) ) ) ) |____| .__|_| |_|_| |_\__, | / / / /|_||___//_/_/_/:: Spring Boot :: (v3.3.0)//笔记背…...

IPv6 NDP 记录

NDP&#xff08;Neighbor Discovery Protocol&#xff0c;邻居发现协议&#xff09; 是 IPv6 的一个关键协议&#xff0c;它组合了 IPv4 中的 ARP、ICMP 路由器发现和 ICMP 重定向等协议&#xff0c;并对它们作出了改进。该协议使用 ICMPv6 协议实现&#xff0c;作为 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(内存管理的基本原理和要求、连续分配管理方式)

一、内存管理的基本原理和要求 内存管理&#xff08;Memory Management&#xff09;是操作系统设计中最重要和最复杂的内容之一。虽然计算机硬件技术一直在飞速发展&#xff0c;内存容量也在不断增大&#xff0c;但仍然不可能将所有用户进程和系统所需要的全部程序与数据放入主…...

【Redis】基于Redis实现秒杀功能

业务的流程大概就是&#xff0c;先判断优惠卷是否过期&#xff0c;然后判断是否有库存&#xff0c;最好进行扣减库存&#xff0c;加入全局唯一id&#xff0c;然后生成订单。 一、超卖问题 真是的场景下可能会有超卖问题&#xff0c;比如开200个线程进行抢购&#xff0c;抢100个…...

Hadoop 使用过程中 15 个常见问题的详细描述、解决方案

目录 问题 1&#xff1a;配置文件路径错误问题描述解决方案Python 实现 问题 2&#xff1a;YARN 资源配置不足问题描述解决方案Python 实现 问题 3&#xff1a;DataNode 无法启动问题描述解决方案Python 实现 问题 4&#xff1a;NameNode 格式化失败问题描述解决方案Python 实现…...

【Flutter 问题系列第 84 篇】如何清除指定网络图片的缓存

这是【Flutter 问题系列第 84 篇】&#xff0c;如果觉得有用的话&#xff0c;欢迎关注专栏。 博文当前所用 Flutter SDK&#xff1a;3.24.3、Dart SDK&#xff1a;3.5.3&#xff0c;网络图片缓存用的插件 cached_network_image: 3.4.1&#xff0c;缓存的网络图像的存储和检索用…...

【UE5】使用基元数据对材质传参,从而避免新建材质实例

在项目中&#xff0c;经常会遇到这样的需求&#xff1a;多个模型&#xff08;例如 100 个&#xff09;使用相同的材质&#xff0c;但每个模型需要不同的参数设置&#xff0c;比如不同的颜色或随机种子等。 在这种情况下&#xff0c;创建 100 个实例材质不是最佳选择。正确的做…...

鸿蒙动画开发07——粒子动画

1、概 述 粒子动画是在一定范围内随机生成的大量粒子产生运动而组成的动画。 动画元素是一个个粒子&#xff0c;这些粒子可以是圆点、图片。我们可以通过对粒子在颜色、透明度、大小、速度、加速度、自旋角度等维度变化做动画&#xff0c;来营造一种氛围感&#xff0c;比如下…...

IDEA2023 创建SpringBoot项目(一)

一、Spring Boot是由Pivotal团队提供的全新框架&#xff0c;其设计目的是用来简化新Spring应用的初始搭建以及开发过程。该框架使用了特定的方式来进行配置&#xff0c;从而使开发人员不再需要定义样板化的配置。 二、快速开发 1.打开IDEA选择 File->New->Project 2、…...

VSCode:终端打开一片空白,无cmd

第一步&#xff1a;找到右下角设置图标 第二步&#xff1a;找到 Terminal - Integrated - Default Profile: Windows: 选择一个本地存在的命令方式&#xff0c;重启即可 也可以直接在右下角直接选择...

Zea maize GO

1.涉及到新旧基因组的转化 B73v4_to_B73v5 &#xff08;davidbioinformatics只支持新版基因组&#xff09; MaizeGDB Map文件下载https://download.maizegdb.org/Pan-genes/B73_gene_xref/小处理脚本&#xff08;制作map文件&#xff09; import pandas as pd# 读取CSV文件 …...

Android开发实战班 - 数据持久化 - 数据加密与安全

在 Android 应用开发中&#xff0c;数据安全至关重要&#xff0c;尤其是在处理敏感信息&#xff08;如用户密码、支付信息、个人隐私数据等&#xff09;时。数据加密是保护数据安全的重要手段&#xff0c;可以有效防止数据泄露、篡改和未经授权的访问。本章节将介绍 Android 开…...

EDA实验设计-led灯管动态显示;VHDL;Quartus编程

EDA实验设计-led灯管动态显示&#xff1b;VHDL&#xff1b;Quartus编程 引脚配置实现代码RTL引脚展示现象记录效果展示 引脚配置 #------------------GLOBAL--------------------# set_global_assignment -name RESERVE_ALL_UNUSED_PINS "AS INPUT TRI-STATED" set_…...

Eclipse 查找功能深度解析

Eclipse 查找功能深度解析 Eclipse 是一款广受欢迎的集成开发环境(IDE),它为各种编程语言提供了强大的开发工具。在本文中,我们将深入探讨 Eclipse 的查找功能,这是开发者日常工作中不可或缺的一部分。无论是查找代码中的特定字符串,还是进行更复杂的搜索,如正则表达式…...

第三百二十九节 Java网络教程 - Java网络UDP套接字

Java网络教程 - Java网络UDP套接字 TCP套接字是面向连接的&#xff0c;基于流。基于UDP的套接字是无连接的&#xff0c;基于数据报。 使用UDP发送的数据块称为数据报或UDP数据包。每个UDP分组具有数据&#xff0c;目的地IP地址和目的地端口号。 无连接套接字在通信之前不建立…...

Leetcode215. 数组中的第K个最大元素(HOT100)

链接 第一次&#xff1a; class Solution { public:int findKthLargest(vector<int>& nums, int k) {sort(nums.begin(),nums.end());int n nums.size();return nums[n-k];} }; 这显然不能出现在面试中&#xff0c;因为面试官考察的不是这个。 正确的代码&#…...

网站 手机网站/惠州百度关键词优化

微信小程序接入腾讯云IM即时通讯&#xff08;会话列表之未读消息&#xff0c;显示最新一条消息开发步骤&#xff09; 1.未读消息思路 首先&#xff0c;获取未读消息第一步就是要先能接收到对方发送的信息&#xff0c;也就是要在官方api中给的监听新消息事件做处理。先看下图需…...

wp标题 wordpress/百度上做优化

document.getElementById 根据 id 获取元素document.getElementsByClassName 根据 class 名获取元素类数组document.getElementsByTagName 根据标签名获取元素类数组document.querySelector 根据 css 选择器获取匹配的第一个元素document.querySelectorAll 根据 css 选择器获取…...

为什么用Vue做网站的很少/优化营商环境应当坚持什么原则

k8s中使用service做四层负载均衡 在kubernetes中&#xff0c;Pod是有生命周期的&#xff0c;如果pod重启IP很有可能就会发生变化。如果我们的服务都是将pod的IP写死&#xff0c;pod的挂掉或者重启&#xff0c;和刚才重启的pod相关联的其他服务就会找不到它所关联的pod&#xff…...

广东省住房城乡建设厅官方网站/做百度推广需要什么条件

为什么80%的码农都做不了架构师&#xff1f;>>> 原文地址:http://www.cnblogs.com/kingboy2008/archive/2011/07/01/2226424.html IE浏览器的兼容性一直是网站开发人员头疼的事情&#xff0c;众所周知&#xff0c;微软的Internet Explorer团队一直在致力于将IE8打造…...

上海公司公开发行股票1984/优化大师哪个好

前言&#xff1a; 习惯了可视化操作git,就把git命令忘得差不多了&#xff0c;但是有些东西还必须命令解决。今天就是遇到了分支合并&#xff0c;代码回滚和代码强制提交。可视化操作不来&#xff0c;只能用git命令操作。 先一步步介绍&#xff1a; 一&#xff1a;代码的基本…...

如何修改网站模版/什么叫seo

下面的学习关于脚本&#xff0c;而学习脚本&#xff0c;变量就显得尤为重要&#xff0c;首先&#xff0c;要对变量有一个初步的认识&#xff1a;只对当前的SHELL有效的变量是本地变量,&#xff1b; 还有就是系统环境变量&#xff1b;变量的使用&#xff0c;可以简化脚本&#x…...