Rust宏编程快速教程

简介:

Rust语言最强大的一个特点就是可以创建和利用宏/Macro。不过创建Rust宏看起来挺复杂,常常令刚接触Rust的开发者心生畏惧。这片文章的目的就是帮助你理解Rust Macro的基本运作原理,学习如何创建自己的Rust宏。

相关链接:在线学编程

1、什么是Rust的宏/Macro?

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8yYpE8g0-1580446818257)(rust-macro/println.png)]

如果你尝试过Rust,应该已经用过Rust的宏了:println!。这个宏可以在终端输出一行文本,并且支持变量的插值。

简单地说,Rust宏让你可以发明自己的语法,编写出可以自行展开的代码,也就是我们通常所说的元编程,你甚至可以用Rust宏来创作自己的DSL。

Rust宏的基本运作机制就是:首先匹配宏规则中定义的模式,然后将匹配结果绑定到变量,最后展开变量替换后的代码。

不理解也没有关系,让我们继续看。

2、如果创建Rust宏/Macro?

可以使用Rust预置的macro_rules!宏来创建一个新的Rust宏。

下图展示了如何创建一个空白的Rust宏:hey!,这个宏什么功能也没有,我们现在只关注它的结构:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-834SEnt9-1580446818259)(rust-macro/hey.png)]

() => {}看起来很神秘,因为它不是标准的rust语法,是macro_rules!这个宏自己发明的,用来表示一条宏规则,=>左边是匹配模式,右边是等待展开的代码:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0Ic6MEaC-1580446818259)(rust-macro/matcher-transcriber.png)]

左边的小括号部分是Rust宏的匹配器/Matcher,用来匹配模式并捕捉变量,这是我们发明自定义语法和DSL的关键所在。

右边的大括号部分是Rust宏的转码器/Transcriber,也就是我们要应用匹配器捕捉到的变量的部分,Rust编译器将利用变量和这部分的代码来生成实际的Rust代码。

类似于Rust中的match语句,在macro_rules!中可以定义多条宏规则,例如:

macro_rules! hey{
  () => {},
  () => {}
}

3、模式匹配与变量捕捉

现在我们看看Rust宏的模式是如何匹配的。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dUkweN6C-1580446818259)(rust-macro/matcher.png)]

在匹配器/Matcher中,$name部分定义了变量名,匹配结果将绑定到该变量以便应用到转码器/Transcriber中。在这个示例中,表示我们将Rust宏的匹配结果存入变量$name

冒号后面的部分被称为选择器/Designator,用于声明我们要匹配的类型。例如在这个示例中,我们使用的是表达式选择器,也就是expr,这告诉Rust:匹配一个表达式,然后存入$name变量。

表达式选择器只是Rust中众多可用选择器中的一个,下面是一些常见的Rust宏选择器:

  • item:条目,例如函数、结构、模块等
  • block:代码块
  • stmt:语句
  • pat:模式
  • expr:表达式
  • ty:类型
  • ident:标识符
  • path:路径,例如 foo、 ::std::mem::replace, transmute::<_, int>, ...
  • meta:元信息条目,例如 #[...]和 #![rust macro...] 属性
  • tt:词条树

那么,现在如何在转码器/Transcriber中应用我们捕捉到的变量?

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RcEsVmRn-1580446818260)(rust-macro/transcriber.png)]

很简单,在Rust宏转码器部分我们只需要在常规的Rust代码中,嵌入匹配器捕捉到的变量就行了,没什么特别之处!

4、编写第一个Rust宏

我们已经了解了如何编写一个Rust宏,现在让我们动手写一个:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PEhGDVwo-1580446818260)(rust-macro/yo.png)]

很简单,对吧?

5、重复模式的提取与利用

我们用的许多Rust宏都可以支持非常多的输入。以vec!宏为例,我们可以这样调用它:vec![rust macro1,2,3,4,5],或者这样:vec![rust macro1,2,3,,4,5,6,7,8]

那么vec!宏是如何实现这一点的?很显然它不会去定义成千上万个变量来逐个保存匹配结果,秘密在于重复模式的匹配:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VfViPALm-1580446818261)(rust-macro/repeat.png)]

我们只需要把希望重复的模式写在$(...)这部分,然后插入分隔符,在这里也就是逗号,最后添加一个*符号,表示重复匹配$()中的模式。

还有点晕?让我们看个具体的例子:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LiHdHrms-1580446818261)(rust-macro/repeat-sample.png)]

在这个示例中,对于hey!宏,我们重复捕捉输入表达式并存入变量$name,也就是说,所有捕捉到的表达式都绑定到变量$name了 —— 不妨把 $name想象成数组变量。

6、用重复模式在Rust中实现Ruby的哈希表语法

如果你之前写过Ruby程序,可能还记得在Ruby中定义哈希表的语法:key => value。现在我们可以用Rust宏来在Rust中实现哈希表的这种定义方法!

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aj3unC4Y-1580446818262)(rust-macro/hash-pattern.png)]

在Rust宏的匹配器部分,我们使用模式$key:expr => $value:expr来分别捕捉$key$value表达式,分隔符为=>。不过现在只能匹配一个键/值对,但是哈希表通常都是多个键值对的。应该如何实现?

答案是使用重复匹配:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kPaMIH09-1580446818262)(rust-macro/hash-repeat.png)]

将我们要匹配的键/值对模式放到$(),*,就可以进行重复匹配了。COOL!!

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-P0aIUZ5M-1580446818262)(rust-macro/hash-repeat-2.png)]

那么,如何应用捕捉到的键/值对?显然,我们应该在Rust宏的转码器中创建哈希表对象,然后将捕捉到的所有键值对插入该哈希表:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-c6CFPpds-1580446818263)(rust-macro/hash-transcriber.png)]

在转码器中,注意代码中的$()*,它的意思是其中的代码会重复展开!

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LYeEUmVK-1580446818263)(rust-macro/hash-expand.png)]

就像你看到的,当我们调用map!("name" => "Finn", "gender" => "Boy")时,我们在生成两段重复的代码。

key => value将被转码为在Rust宏的转码器/transcriber中指定的代码,也就是hm.insert($key, $value),其中$key$value是我们在Rust宏的匹配器部分捕捉到的变量。

好了,让我们看看完整的map!宏实现:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JfUy7ZXL-1580446818264)(rust-macro/map.png)]

只用了几行代码,我们就创建了一个功能完整的Rust宏!现在让我们写个小程序测试一下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1BYJjuNj-1580446818264)(rust-macro/map-test.png)]

COOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOL.


原文链接:Rust宏编程新手指南 — 汇智网

目录
相关文章
|
5天前
|
Rust 算法 安全
如何学习Rust编程?
【10月更文挑战第12天】如何学习Rust编程?
17 1
|
7天前
|
Rust 编译器 开发者
Rust宏之derive的设计及实战
【10月更文挑战第18天】在 Rust 中,`derive` 宏是一种自动生成代码的工具,可为结构体和枚举类型自动实现特定 trait,减少重复代码。它通过语法糖简化代码,支持 Debug、Clone、PartialEq 等 trait 的自动实现,并允许开发者自定义 `derive` 宏以扩展功能。
|
8天前
|
Rust 安全 Java
探索Rust在系统级编程中的应用
【10月更文挑战第9天】Rust语言以其现代化设计、安全性和高性能,在系统级编程领域逐渐崭露头角。本文探讨Rust在操作系统开发、设备驱动、嵌入式系统和网络编程中的应用,介绍其核心优势及实施步骤,帮助读者了解如何在项目中有效利用Rust。
|
17天前
|
Rust 安全 Java
探索Rust在系统编程中的崛起
Rust 是一种由 Mozilla 研究院开发的现代系统编程语言,以其在安全性、并发性和内存管理方面的优势,逐渐成为开发者的新宠。Rust 提供内存安全保证且性能媲美 C/C++,支持跨平台开发,并具备强大的并发编程工具。本文将介绍 Rust 的核心优势、工作原理及实施方法,探讨其在系统编程中的崛起及其面临的挑战。尽管 Rust 学习曲线较陡,但其广泛的应用场景和不断壮大的社区使其成为构建高性能、安全应用的理想选择。
|
1月前
|
Rust 网络协议 安全
Rust在系统编程中的案例分享
Rust在系统编程中的案例分享
47 10
|
28天前
|
Rust 安全 前端开发
30天拿下Rust之图形编程
30天拿下Rust之图形编程
30 0
|
2月前
|
Rust 安全 JavaScript
探索Rust在系统编程领域的前景:虚拟机和编译器开发的新篇章
【8月更文挑战第31天】在系统编程领域,性能与安全性至关重要。Rust作为一种新兴语言,凭借其独特的内存安全和并发特性,正逐渐成为虚拟机和编译器开发的首选。本文通过案例分析,探讨Rust在这些领域的应用,例如Facebook的Compiler VM (CVM)项目和实验性的JavaScript JIT编译器Mithril。Rust的静态类型系统和所有权模型确保了高性能和安全性,而其强大的包管理和库生态则简化了虚拟机的开发。随着Rust社区的不断成熟,预计未来将有更多基于Rust的创新项目涌现,推动系统编程的发展。对于追求高性能和安全性的开发者而言,掌握Rust将成为一个重要战略方向。
59 1
|
2月前
|
开发者 vr&ar 机器学习/深度学习
Xamarin 开发者的未来趋势展望:掌握跨平台开发新机遇,引领移动应用创新潮流与技术变革方向
【8月更文挑战第31天】Xamarin 作为领先的跨平台开发框架,通过 C# 和 .NET 框架实现一次编写、多平台运行,简化了 iOS、Android 和 Windows 应用的开发流程。未来几年,Xamarin 开发者将面临跨平台开发普及、云集成、机器学习、AR/VR、性能优化及安全性等关键趋势。通过学习新技术并积极采用新工具,开发者能够提升应用质量和用户体验,如利用 Azure AD B2C 实现身份认证,从而在竞争激烈的市场中脱颖而出。
55 0
|
2月前
|
监控 UED 开发者
从设计到监控:用Xamarin打造高可用性移动应用的实战策略与案例深度剖析
【8月更文挑战第31天】在数字化时代,移动应用成为生活工作的重要组成部分,其稳定性和可靠性至关重要。Xamarin作为跨平台开发框架,已广受认可,但如何确保应用高可用性是开发者面临的挑战。本文以电商应用“SmartShop”为例,从设计、异常处理、性能优化、多线程及测试监控五个方面探讨构建高可用性Xamarin应用的最佳实践。通过模块化设计、有效异常处理、性能优化、多线程技术和全面测试监控,确保应用稳定高效,提升用户体验。
33 0
|
2月前
|
Rust 开发者 C#
解锁Rust高手的秘密武器:模式匹配与宏,学会这一招,编程效率翻倍!
【8月更文挑战第31天】Xamarin 是移动应用开发领域的强大跨平台工具,采用 C# 语言,具备高代码复用性、熟悉开发语言及接近原生性能等优势。开发者可通过共享项目实现多平台业务逻辑复用,简化开发流程。然而,Xamarin 也存在学习曲线陡峭、需处理平台差异及第三方库兼容性等问题。总体而言,Xamarin 在提高开发效率的同时,也对开发者提出了新的挑战。
22 0