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

【第四课】rust声明式宏理解与实战

目录

前言

理解宏

实战宏


前言

上一课在介绍vector时,我们再一次提到了rust中的宏,在初始化vector时使用了vec!宏,当时补了一句有机会会好好说明一下rust中的宏,并且写一个hashmap宏来初始化hashmap。想了想一直介绍基本语法还是比较枯燥乏味的,所以这节课我们介绍一点有意思的,我们看看rust中的声明式宏。

理解宏

宏是一种元编程,是一种用代码去生成代码的技术,如果有了解过flink/spark的同学,在flink/spark中有很多算子都是靠代码生成的,事先定义好模版,然后生成对应的代码,最后执行。

rust中的宏也是依赖代码去生成代码。在编译期间会生成对应的代码,第一次学习宏,理解生成代码这一点很重要。

rust中的宏有好几种,我们见到的println! 和 vec!都是声明式宏,本文也主要介绍声明式宏,贪多必失,我们一个一个来。

我们在上一节课使用了vec!宏,我们来看看vec!的定义。

以#开头的也是rust中一种宏,通过字面意思都能看出来个大概,我们来一个一个过一下。

#[cfg(all(not(no_global_oom_handling), not(test)))]

这是条件编译属性。牢记宏是在生成代码,这里的意思就是在哪些条件下编译生成代码,no_global_oom_handling表示禁用全局oom处理,test表示测试环境,前面有not,表示在没有禁用全局oom处理和测试的条件下,这个宏才是可以被编译的,就是说在测试环境和禁用全局oom处理的情况下代码无法被编译。

#[macro_export]

表示这个宏可以被导出,可以被导出的意思就是,可以被别的模块导入使用

#[stable(feature = "rust1", since = "1.0.0")]

这个就更明显了,从rust1.0开始的稳定feature

#[rustc_diagnostic_item = "vec_macro"]

给这个宏取了一个名字,在诊断的时候有用

#[allow_internal_unstable(rustc_attrs, liballoc_internals)]

允许使用一些内部不稳定的东西,我也没太看懂,但感觉也不必过于纠结

接下来看宏的定义部分

macro_rules! vec 

这一行定义了一个叫vec的宏,后面{}中包含的是这个宏的具体内容,我们一个一个部分

() => (
        $crate::vec::Vec::new()
    );

这个匹配的是vec![]的情况,简单明了,如果调用的宏没有提供参数的话,生成的是Vec::new()函数

($elem:expr; $n:expr) => (
        $crate::vec::from_elem($elem, $n)
    );

这个匹配的是vec![1;3]的情况,生成的代码是std::vec::from_elem(1, 3);看起来也比较简单

($($x:expr),+ $(,)?) => (
        <[_]>::into_vec(
            // This rustc_box is not required, but it produces a dramatic improvement in compile
            // time when constructing arrays with many elements.
            #[rustc_box]
            $crate::boxed::Box::new([$($x),+])
        )
    );

这个匹配的是vec![1,2,3,4,5]的情况,看起来是最复杂的一个了,我们来拆解一下看一看,很像正则对不对,

$($x:expr),+ 是第一部分,+表示有一个或多个$($x:expr), 注意逗号也是一部分哦,expr是表达式,并且取了一个名字x

$(,)?是第二部分,?表示前面的部分是可选的,意思就是也许会有一个逗号在末尾

#[cfg(all(not(no_global_oom_handling), not(test)))]
#[macro_export]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_diagnostic_item = "vec_macro"]
#[allow_internal_unstable(rustc_attrs, liballoc_internals)]
macro_rules! vec {() => ($crate::vec::Vec::new());($elem:expr; $n:expr) => ($crate::vec::from_elem($elem, $n));($($x:expr),+ $(,)?) => (<[_]>::into_vec(// This rustc_box is not required, but it produces a dramatic improvement in compile// time when constructing arrays with many elements.#[rustc_box]$crate::boxed::Box::new([$($x),+])));
}

实战宏

我们来仿造vec宏,来编写一个hashmap的宏吧

我们的目的是想完成一个hashmap宏,接收二元组作为map的key和value,下面代码仿造vec宏的写法,我们来一一解读一下。

() => {},这是默认的格式

$(($key:expr, $value:expr)),* 这表示($key:expr, $value:expr)这个二元组会重复多次,使用逗号分隔。

我们在定义中先定义了一个HashMap,然后重复执行insert操作,最后返回hashmap

当我们在编译hashmap!宏时let my_map = hashmap!(("a",1))

实际上,代码会被替换为let my_map = {

let mut t = Hashmap::new();

t.insert("a",1);

t

}

讲到这里,其实可以很好理解为什么声明宏是模版代码了,我们定义了模版,在编译期间,将模版代码替换执行的代码。

use std::collections::HashMap;macro_rules! hashmap {($(($key:expr, $value:expr)),*) => {{let mut t = HashMap::new();$(t.insert($key, $value);)*t}}
}fn main() {let v1 = vec![1; 3];let v2 = std::vec::from_elem(1, 3);let my_map = hashmap!(("a",1));println!("my_map['a']={}", my_map["a"]);
}

总结

这节课承接是上节课在介绍vector和hashmap时,穿插进来的支线任务,下节会回归到主线,继续介绍rust中的基本语法,了解一下rust中的流程控制。这节课由vec宏引起,介绍了rust中的声明式宏,类似函数,但是比函数更加灵活和强大,通过模版代码的方式完成功能。因为是在编译期间就完成了,所以并不会有运行时的性能影响,关于宏的其他内容,我们在后面再慢慢提起。

相关文章:

【第四课】rust声明式宏理解与实战

目录 前言 理解宏 实战宏 前言 上一课在介绍vector时&#xff0c;我们再一次提到了rust中的宏&#xff0c;在初始化vector时使用了vec!宏&#xff0c;当时补了一句有机会会好好说明一下rust中的宏&#xff0c;并且写一个hashmap宏来初始化hashmap。想了想一直介绍基本语法还…...

渗透测试--Linux下的文件传输方法

渗透测试过程中&#xff0c;我们经常会需要文件传输&#xff0c;本文主要探讨Linux主机上我们对文件传输的方法。 编码方式 Linux 检查MD5 md5sum id_rsa Linux Base64 编码/解码 编码 cat id_rsa |base64 -w 0;echo 解码 echo -n LS0tLS1CRUdJTiBPUEVOU1NIIFBSSVZBVE…...

浅议Flink中的通讯工具: Akka

在Flink中&#xff0c;各个组件之间需要频繁交换数据和控制信息。Flink选择了基于Actor模型的Akka框架作为通信基础。 Akka是什么 Actor模型 Actor模型是用于单个进程中并发的场景。 在Actor模型中&#xff1a; ActorSystem负责管理actor生命周期 将每个实体视为独立的 Ac…...

基于YOLOv8深度学习的独居老人情感状态监护系统(PyQt5界面+数据集+训练代码)

本研究提出了一种创新的独居老人情感状态监护系统&#xff0c;基于YOLOV8深度学习模型&#xff0c;旨在通过对老年人面部表情的实时监测与分析&#xff0c;来精准识别其情感变化&#xff0c;从而提高独居老人的生活质量&#xff0c;确保其心理健康。本系统通过整合先进的YOLOV8…...

Qt添加外部库:静态库和动态库,批量添加头文件

Qt添加外部库需要知道库文件的位置才能正确链接&#xff0c;如果是静态库&#xff0c;要确保LIBS变量中包含正确的库文件路径和库文件名;如果是动态库&#xff0c;除了库路径外&#xff0c;还需要考虑动态库的加载路径。在 Windows 下&#xff0c;可以将动态库所在路径添加到系…...

Unity类银河战士恶魔城学习总结(P132 Merge skill tree with skill Manager 把技能树和冲刺技能相组合)

【Unity教程】从0编程制作类银河恶魔城游戏_哔哩哔哩_bilibili 教程源地址&#xff1a;https://www.udemy.com/course/2d-rpg-alexdev/ 本章节实现了解锁技能后才可以使用技能&#xff0c;先完成了冲刺技能的锁定解锁 Dash_Skill.cs using System.Collections; using System…...

Docker入门之Windows安装Docker初体验

在之前我们认识了docker的容器&#xff0c;了解了docker的相关概念&#xff1a;镜像&#xff0c;容器&#xff0c;仓库&#xff1a;面试官让你介绍一下docker&#xff0c;别再说不知道了 之后又带大家动手体验了一下docker从零开始玩转 Docker&#xff1a;一站式入门指南&#…...

DNS实验作业

实验要求 1.搭建dns服务器能够对自定义的正向或者反向域完成数据解析查询。 2.配置从DNS服务器&#xff0c;对主dns服务器进行数据备份。 实验步骤&#xff1a; 1.关闭防护墙 [rootlocalhost ~]# systemctl stop firewalld [rootlocalhost ~]# setenforce 0 2.正向解析 [rootlo…...

CSS回顾-CSS选择器详解

一、引言 我来填坑啦&#xff01;之前在CSS基础知识详解中介绍过&#xff0c;CSS 是一门基于规则的语言。是由选择器与样式信息组成&#xff1a;选择器 {样式信息}。CSS 选择器是 CSS 规则的关键&#xff0c;能精准定位 HTML 元素&#xff0c;CSS3 新增选择器更是增强了设计能…...

FFMPEG录像推流时遇到的问题

FFMPEG录像推流时遇到的问题&#xff0c;记录一下供大参考 1. ret avformat_write_header( ofmt_ctx, NULL ); 执行写入头后&#xff0c;所有的流的时间基都会被内部重新设置&#xff0c;所以并不你想象的把原来的时间直接入到avPACKET中就可以发送了。必须要把你每个流的P…...

【STM32+K210项目】基于K210智能人脸识别+车牌识别系统(完整工程资料源码)

运行效果: 基于K210的智能人脸与车牌识别系统工程 目录: 运行效果: 目录: 前言: 一、国内外研究现状与发展趋势 二、相关技术基础 2.1 人脸识别技术 2.2 车牌识别技术 三、智能小区门禁系统设计 3.1 系统设计方案 3.2 系统设计目标 3.3 智能小区门禁系统硬件设计 3.3.1 控…...

Unity脚本基础规则

Unity脚本基础规则 如何在Unity中创建一个脚本文件&#xff1f; 在Project窗口中的Assets目录下&#xff0c;选择合适的文件夹&#xff0c;右键&#xff0c;选择第一个Create&#xff0c;在新出现的一栏中选择C# Script&#xff0c;此时文件夹内会出现C#脚本图标&#xff0c;…...

基于AIRTEST和Jmeter、Postman的自动化测试框架

基于目前项目和团队技术升级&#xff0c;采用了UI自动化和接口自动化联动数据&#xff0c;进行相关测试活动&#xff0c;获得更好的测试质量和测试结果。...

使用 Azure OpenAI 服务对数据进行联合 SharePoint 搜索

作者&#xff1a;来自 Elastic Gustavo Llermaly 使用 Azure OpenAI 服务处理你的数据&#xff0c;并使用 Elastic 作为向量数据库。 在本文中&#xff0c;我们将探索 Azure OpenAI 服务 “On Your Data”&#xff0c;使用 Elasticsearch 作为数据源。我们将使用 Elastic Shar…...

JavaScript学习笔记 1】初识JS

目录 一、JS是什么&#xff1f; 二、JS的作用&#xff1f; 三、JS的组成 四、JS的书写位置 1. 内部JS 2. 外部JS(外部导入) 3. 内联JS 4. 练习 五、JS的注释与结束符 1. 注释 2. 结束符 3. JS该不该加分号&#xff1f; 六、JS的输入和输出语法 1. 输出语法 a. 输出在页面中 b. …...

Linux-Samba

文章目录 Samba配置服务配置 &#x1f3e1;作者主页&#xff1a;点击&#xff01; &#x1f916;Linux专栏&#xff1a;点击&#xff01; ⏰️创作时间&#xff1a;2024年11月18日13点20分 Samba配置 Samba是一个能让 Linux 系统应用与 Microsoft 网络通讯协议的软件&#x…...

【Java Web】JSON 以及 JSON 转换

JSON&#xff08;JavaScript Object Notation&#xff09;一种灵活、高效、轻量级的数据交换格式&#xff0c;广泛应用于各种数据交换和存储场景。 基本特点 1、简单易用&#xff1a;JSON格式非常简单&#xff0c;易于理解和使用。 2、轻量级&#xff1a;相比XML等其他数据格…...

Qt 元对象系统

Qt 元对象系统 Qt 元对象系统1. 元对象的概念2. 元对象系统的核心组件2.1 QObject2.2 Q_OBJECT 宏2.3 Meta-Object Compiler (MOC) 3. 信号与槽3.1 基本概念信号与槽的本质信号和槽的关键特征 3.2 绑定信号与槽参数解析断开连接 3.3 标准信号与槽查找标准信号与槽使用示例规则与…...

鸿蒙实战:使用隐式Want启动Ability

文章目录 1. 实战概述2. 实现步骤2.1 创建鸿蒙应用项目2.2 修改Index.ets代码2.3 创建LuzhouAbility2.4 创建Luzhou页面2.5 设置模块配置文件 3. 测试效果4. 实战总结 1. 实战概述 本次鸿蒙应用实战&#xff0c;先创建项目“ImplicitWantStartAbility”&#xff0c;接着修改In…...

go-zero(二) api语法和goctl应用

go-zero api语法和goctl应用 在实际开发中&#xff0c;我们更倾向于使用 goctl 来快速生成代码。 goctl 可以根据 api快速生成代码模板&#xff0c;包括模型、逻辑、处理器、路由等&#xff0c;大幅提高开发效率。 一、构建api demo 现在我们通过 goctl 创建一个最小化的 HT…...

C++:std::is_convertible

C++标志库中提供is_convertible,可以测试一种类型是否可以转换为另一只类型: template <class From, class To> struct is_convertible; 使用举例: #include <iostream> #include <string>using namespace std;struct A { }; struct B : A { };int main…...

什么是库存周转?如何用进销存系统提高库存周转率?

你可能听说过这样一句话&#xff1a; “利润不是赚出来的&#xff0c;是管出来的。” 尤其是在制造业、批发零售、电商这类“货堆成山”的行业&#xff0c;很多企业看着销售不错&#xff0c;账上却没钱、利润也不见了&#xff0c;一翻库存才发现&#xff1a; 一堆卖不动的旧货…...

linux arm系统烧录

1、打开瑞芯微程序 2、按住linux arm 的 recover按键 插入电源 3、当瑞芯微检测到有设备 4、松开recover按键 5、选择升级固件 6、点击固件选择本地刷机的linux arm 镜像 7、点击升级 &#xff08;忘了有没有这步了 估计有&#xff09; 刷机程序 和 镜像 就不提供了。要刷的时…...

cf2117E

原题链接&#xff1a;https://codeforces.com/contest/2117/problem/E 题目背景&#xff1a; 给定两个数组a,b&#xff0c;可以执行多次以下操作&#xff1a;选择 i (1 < i < n - 1)&#xff0c;并设置 或&#xff0c;也可以在执行上述操作前执行一次删除任意 和 。求…...

【配置 YOLOX 用于按目录分类的图片数据集】

现在的图标点选越来越多&#xff0c;如何一步解决&#xff0c;采用 YOLOX 目标检测模式则可以轻松解决 要在 YOLOX 中使用按目录分类的图片数据集&#xff08;每个目录代表一个类别&#xff0c;目录下是该类别的所有图片&#xff09;&#xff0c;你需要进行以下配置步骤&#x…...

优选算法第十二讲:队列 + 宽搜 优先级队列

优选算法第十二讲&#xff1a;队列 宽搜 && 优先级队列 1.N叉树的层序遍历2.二叉树的锯齿型层序遍历3.二叉树最大宽度4.在每个树行中找最大值5.优先级队列 -- 最后一块石头的重量6.数据流中的第K大元素7.前K个高频单词8.数据流的中位数 1.N叉树的层序遍历 2.二叉树的锯…...

深度学习习题2

1.如果增加神经网络的宽度&#xff0c;精确度会增加到一个特定阈值后&#xff0c;便开始降低。造成这一现象的可能原因是什么&#xff1f; A、即使增加卷积核的数量&#xff0c;只有少部分的核会被用作预测 B、当卷积核数量增加时&#xff0c;神经网络的预测能力会降低 C、当卷…...

JAVA后端开发——多租户

数据隔离是多租户系统中的核心概念&#xff0c;确保一个租户&#xff08;在这个系统中可能是一个公司或一个独立的客户&#xff09;的数据对其他租户是不可见的。在 RuoYi 框架&#xff08;您当前项目所使用的基础框架&#xff09;中&#xff0c;这通常是通过在数据表中增加一个…...

HarmonyOS运动开发:如何用mpchart绘制运动配速图表

##鸿蒙核心技术##运动开发##Sensor Service Kit&#xff08;传感器服务&#xff09;# 前言 在运动类应用中&#xff0c;运动数据的可视化是提升用户体验的重要环节。通过直观的图表展示运动过程中的关键数据&#xff0c;如配速、距离、卡路里消耗等&#xff0c;用户可以更清晰…...

Java + Spring Boot + Mybatis 实现批量插入

在 Java 中使用 Spring Boot 和 MyBatis 实现批量插入可以通过以下步骤完成。这里提供两种常用方法&#xff1a;使用 MyBatis 的 <foreach> 标签和批处理模式&#xff08;ExecutorType.BATCH&#xff09;。 方法一&#xff1a;使用 XML 的 <foreach> 标签&#xff…...