Rust中的宏:声明宏和过程宏
Rust中的声明宏和过程宏
宏是Rust语言中的一个重要特性,它允许开发人员编写可重用的代码,以便在编译时扩展和生成新的代码。宏可以帮助开发人员减少重复代码,并提高代码的可读性和可维护性。Rust中有两种类型的宏:声明宏和过程宏。
声明宏:
声明宏是一种用于定义新的宏的语法。它使用macro_rules!关键字定义,并遵循特定的语法规则。声明宏通常用于定义简单的宏,例如计算两个数字之和或打印一条消息。
例如,下面是一个简单的声明宏,用于计算两个数字之和:
macro_rules! add {
($x:expr, $y:expr) => {
$x + $y
};
}
fn main() {
let x = 5;
let y = 6;
println!("{}", add!(x, y));
}
复制代码
在上面的示例中,我们定义了一个名为add的声明宏。该宏接受两个参数:$x和$y,并使用=>符号将参数映射到表达式$x + $y。在主函数中,我们使用add!(x, y)调用该宏,并将结果打印到控制台。
过程宏:
过程宏是另一种用于定义新的宏的语法。与声明宏不同,过程宏使用特殊的函数来定义,并可以接受任意数量的参数。过程宏通常用于定义更复杂、更强大的宏,例如实现自定义派生或生成新的类型。
例如,下面是一个简单的过程宏,用于计算两个数字之和:
use proc_macro::TokenStream;
#[proc_macro]
pub fn add(input: TokenStream) -> TokenStream {
let mut iter = input.into_iter();
let x = iter.next().unwrap();
let _comma = iter.next().unwrap();
let y = iter.next().unwrap();
let result = format!("{} + {}", x, y);
result.parse().unwrap()
}
fn main() {
let x = 5;
let y = 6;
println!("{}", add!(x, y));
}
复制代码
在上面的示例中,我们定义了一个名为add的过程宏。该函数使用#[proc_macro]属性标记,并接受一个名为input的参数。该参数表示传递给该宏的TokenStream。在函数体内部,我们使用迭代器来访问TokenStream中的每个元素,并使用format!宏将其格式化为字符串。最后,我们将结果转换为TokenStream并返回。
声明宏和过程宏的比较:
声明宏和过程宏都可以用于定义新的宏,但它们之间存在一些差异。声明宏更简单、易于使用,但功能有限;而过程宏更强大、灵活,但需要更多的编码技巧。
例如,在上面给出的示例中,我们可以看到声明宏和过程宏都可以用于计算 两个数字之和。但是,声明宏只能接受固定数量的参数,并且必须遵循特定的语法规则。而过程宏则可以接受任意数量的参数,并且可以使用任意的Rust代码来定义宏的行为。
此外,声明宏和过程宏在实现方式上也有所不同。声明宏是在编译时扩展的,这意味着它们在编译器内部被处理。而过程宏则是在编译时调用的,这意味着它们在编译器外部被处理。这种差异使得过程宏可以访问更多的编译器信息,并且可以使用更复杂的算法来生成新的代码。
结论:
总之,Rust中的宏是一种强大的工具,可以帮助开发人员编写可重用、高效和灵活的代码。无论是声明宝还是过程宝,都值得开发人员学习和掌握。通过使用宏,开发人员可以减少重复代码,并提高代码的可读性和可维护性。因此,如果您正在使用Rust语言进行软件开发,那么了解宏是非常重要的。from刘金,转载请注明原文链接。感谢!
Rust中的宏:声明宏和过程宏的更多相关文章
- Sass--混合宏--声明宏
如果你的整个网站中有几处小样式类似,比如颜色,字体等,在 Sass 可以使用变量来统一处理,那么这种选择还是不错的.但当你的样式变得越来越复杂,需要重复使用大段的样式时,使用变量就无法达到我们目了.这 ...
- 在 C++ 程序中只使用 const 常量而不使用宏常量
在 C++ 程序中只使用 const 常量而不使用宏常量,即 const 常量完 全取代宏常量. #include <iostream> /* run this program using ...
- 编写Java程序,模拟五子棋博弈过程中的异常声明和异常抛出
返回本章节 返回作业目录 需求说明: 模拟五子棋博弈过程中的异常声明和异常抛出,判断用户所下棋子的位置,是否超越了棋盘的边界. 棋盘的横坐标的范围为0-9,纵坐标范围为0-14,如果用户所放棋子的坐标 ...
- 刷完欧拉计划中难度系数为5%的所有63道题,我学会了Rust中的哪些知识点?
我为什么学Rust? 2019年6月18日,Facebook发布了数字货币Libra的技术白皮书,我也第一时间体验了一下它的智能合约编程语言MOVE,发现这个MOVE是用Rust编写的,看来想准确理解 ...
- C++中的inline声明
C++中的inline声明 1. inline函数(摘自C++ Primer的第三版) 在函数声明或定义中函数返回类型前加上关键字inline即把函数指定为内联函数. inline int min(i ...
- 嵌入式C语言自我修养 12:有一种宏,叫可变参数宏
12.1 什么是可变参数宏 在上面的教程中,我们学会了变参函数的定义和使用,基本套路就是使用 va_list.va_start.va_end 等宏,去解析那些可变参数列表我们找到这些参数的存储地址后, ...
- 宏定义(无参宏定义和带参宏定义),C语言宏定义详解
1.宏定义说明 宏定义是比较常用的预处理指令,即使用"标识符"来表示"替换列表"中的内容.标识符称为宏名,在预处理过程中,预处理器会把源程序中所有宏名,替换成宏 ...
- Rust 中的类型转换
1. as 运算符 as 运算符有点像 C 中的强制类型转换,区别在于,它只能用于原始类型(i32 .i64 .f32 . f64 . u8 . u32 . char 等类型),并且它是安全的. 例 ...
- 【译】理解Rust中的Futures (一)
原文标题:Understanding Futures In Rust -- Part 1 原文链接:https://www.viget.com/articles/understanding-futur ...
- Rust 中的继承与代码复用
在学习Rust过程中突然想到怎么实现继承,特别是用于代码复用的继承,于是在网上查了查,发现不是那么简单的. C++的继承 首先看看c++中是如何做的. 例如要做一个场景结点的Node类和一个Sprit ...
随机推荐
- link和@import的对比
概念的区别 @import 是css的语法规则: link 是HTML标签 用途的区别 @import 是css语法,只能用来导入样式文件: link 除了引入样式,还可引入其他资源文件 加载顺序 ...
- Docker 安装 MySQL5.7
1.拉取数据库镜像 docker pull mysql:5.7 docker images命令查看镜像是否下载成功 docker images 2.配置mysql 创建mysql目录,用于存放mysq ...
- 如何快速开发一套cesium三维系统
首先我们需要明确我们做的三维应该具有哪些功能,常见的三维系统主要用于展示三维数据,常见的功能应该有,缩放平移,漫游浏览,定位,量测,图层控制等基础功能.在这些基础功能上根据业务需要,再继续扩展,添加一 ...
- python学习记录(六)-系统内置模块
序列化 什么是序列化?序列化是指把python中的数据以文本或二进制形式进行转换,还能反序列化为原来的数据 为什么需要序列化?便于数据在程序与网络之间的传输和存储 json:文本序列化 pickle: ...
- springboot修改事务隔离级别
[SpringBoot]事务的隔离级别.Spring的事务传播机制_51CTO博客_springboot事务隔离级别
- Oracle 取Group By 第一条
select *from (select emp.*,row_number() over(partition by deptno order by rownum) cn from emp)where ...
- github fork 别人的项目源作者更新后如何同步更新
如下 左边选择我们拷贝的库 右边选择原工程 如下 点击箭头指向的位置 然后选择右边原工程目录
- RPA的概念和优势
大多数人每天都会使用到一些机器人流程自动化的工具,例如读取邮件和系统,计算.生成文件和报告.而在未来,那些你不想做的枯燥的工作,也许真的可以不做了,重复化.标准化的工作都可以让机器人帮你完成.想必此刻 ...
- 如何在 Apinto 实现 HTTP 与gRPC 的协议转换 (上)
什么是 gRPC 像gRPC是由google开发的一个高性能.通用的开源 RPC 框架,主要面向移动应用开发且基于HTTP/2协议标准而设计,同时支持大多数流行的编程语言. gRPC基于 HTTP/2 ...
- windows作业系统部署nfs服务
文件共享的需求是如何产生的? 据说当年美国和苏联冷战期间,双方都有摧毁对方的能力.而苏联 不怕死的性格让美国人多少有些害怕.美国当时害怕自己的军事指挥中心被苏联摧毁.于是,美国建立了阿帕网,并把自己的 ...