热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Rust1.7.0的macro宏-语法分析和使用举例

macro宏的概念在很多语言中都有。通常情况下,宏的机制是在预编译阶段对已经定义的宏进行替换或者expanded展开,即:把宏按照名称替换成宏的内容。Rust中的宏,与众不同!

macro 宏的概念在很多语言中都有。

通常情况下,宏的机制是在预编译阶段对已经定义的宏进行替换或者 expanded 展开 ,即:把宏按照名称替换成宏的内容。

Rust 中的宏,与众不同!

Rust中的宏,也是在预编译阶段进行处理。宏不仅仅是替换内容和展开,还可以像功能函数一样,接收参数、调用其他的宏。

一、简单的宏

宏的名称和功能函数名称很像,只不过在函数名称后面有一个叹号!

一个简单的宏定义和调用:

macro_rules! say_hello{  
()=>(
println!("Hello");
)
}

fn main(){
say_hello!()
}

解释一下:
macro_rules! 声明一个宏,say_hello 是宏的名字,say_hello后面是一对大括号,是宏的内容体。

大括号里面的=>前面的 ( ) 表示这个宏没有输入参数。
在这个宏内部,调用了另外一个宏 println!

在main()功能函数中调用宏。因为这个宏和调用的功能函数在一个文件中,所以不需要额外的导出和引入宏的声明。

当然,宏的内容体除了用 {}大括号之外,还可以使用 (); 和 [];

macro_rules! say_hello (
()=>(
println!("Hello");
)
);
    macro_rules! say_hello [
()=>(
println!("Hello");
)
];

⚠ 注意:

  • 使用大括号的时候,大括号后面没有分号;
  • 而使用()和[]的时候,后面有一个分号。

❌如果大括号{}有分号;或者()和[]没有分号都会编译错误。

⚠ 注意:

另一个需要注意的是,宏的输入参数是包含在宏内容体内的!!!

二、带参数的宏

下面定义一个带参数的宏 print_hello

macro_rules! print_hello{
($msg:expr) =>(
println!("hello{}", $msg);
)
}

fn main(){
print_hello!(",world!");
}

上面定义了一个 print_hello 宏,把上面的代码分解成 4 个部分:

第一个部分:宏声明

macro_rules! print_hello 
  • macro_rules! 是宏定义关键字,注意后面有 ! 叹号
  • 后面跟宏的名称 这是定义宏的名称

第二部分:宏的内容边界 {一对大括号}

macro_rules! print_hello {

}

第三部分:宏的内容 -大括号中的内容

大括号中的内容被称为 macro rule 宏规则。一个宏可以包含任意(0 -n)多个 macro rule 宏规则。

($msg:expr) =>( println!("hello{}",  $msg) );
($msg:expr) =>{ println!("hello{}", $msg) };
($msg:expr) =>[ println!("hello{}", $msg) ];

($msg:expr) => ( println!("hello{}", $msg); );
($msg:expr) => { println!("hello{}", $msg); };
($msg:expr) => [ println!("hello{}", $msg); ];

以上 6 句 作用完全一致!

宏规则的格式应该是这样的:

( ) => {  };
( ) => [ ];
( ) => ( );
  1. 每个宏规则有一个 => ;
  2. 在 => 左面的小括号是该规则的输入参数,里面的形式是一个 叫做 matcher 匹配器;
  3. 在 => 右面的括号里是宏的内容,需要被执行或者替换,叫做 transcriber 转换器,可以是语句、表达式等。

以上三行代码等同。

matcher 和 transcriber 会在 后面的文章中详细说明。

前面说过,宏的参数是包含在宏内容体内的!
对比一下功能函数的声明格式:

 fn fn_name(x:i32,y:u32){

}

功能函数的输入参数通过 fn_name 后面的小括号传入,参数可能是 0 个或者多个,但是所有的参数一定是在这个括号中声明。

来看看这段代码:

macro_rules! foo {
(x => $e:expr) => (println!("mode X: {}", $e));
(y => $e:expr) => (println!("mode Y: {}", $e));
}

fn main() {
foo!(x => 7);
foo!(y => 3);
}

宏的输入不是通过参数列表传入的!而是通过 match 的方式进行查找或者匹配的。
当匹配到 x => 7 ,则执行 mode X: 7
当匹配到 y => 3 ,则执行 mode Y: 3

第四部分:宏调用

print_hello!(",world!");

调用方式,使用宏名称后面加!叹号,叹号后面跟一个括号表示输入参数。


推荐阅读
  • python模块之正则
    re模块可以读懂你写的正则表达式根据你写的表达式去执行任务用re去操作正则正则表达式使用一些规则来检测一些字符串是否符合个人要求,从一段字符串中找到符合要求的内容。在 ... [详细]
  • 本文介绍了 Go 语言中的高性能、可扩展、轻量级 Web 框架 Echo。Echo 框架简单易用,仅需几行代码即可启动一个高性能 HTTP 服务。 ... [详细]
  • iOS 不定参数 详解 ... [详细]
  • malloc 是 C 语言中的一个标准库函数,全称为 memory allocation,即动态内存分配。它用于在程序运行时申请一块指定大小的连续内存区域,并返回该区域的起始地址。当无法预先确定内存的具体位置时,可以通过 malloc 动态分配内存。 ... [详细]
  • 2020年9月15日,Oracle正式发布了最新的JDK 15版本。本次更新带来了许多新特性,包括隐藏类、EdDSA签名算法、模式匹配、记录类、封闭类和文本块等。 ... [详细]
  • 我有一个从C项目编译的.o文件,该文件引用了名为init_static_pool ... [详细]
  • 使用HTML和JavaScript实现视频截图功能
    本文介绍了如何利用HTML和JavaScript实现从远程MP4、本地摄像头及本地上传的MP4文件中截取视频帧,并展示了具体的实现步骤和示例代码。 ... [详细]
  • C语言编写线程池的简单实现方法
    2019独角兽企业重金招聘Python工程师标准好文章,一起分享——有时我们会需要大量线程来处理一些相互独立的任务,为了避免频繁的申请释放线程所带 ... [详细]
  • 兆芯X86 CPU架构的演进与现状(国产CPU系列)
    本文详细介绍了兆芯X86 CPU架构的发展历程,从公司成立背景到关键技术授权,再到具体芯片架构的演进,全面解析了兆芯在国产CPU领域的贡献与挑战。 ... [详细]
  • 探讨CUDA代码中的内联汇编指令‘ld’和‘add’为何出现参数不匹配的编译错误,并提供解决方案。 ... [详细]
  • 【妙】bug称它为数组越界的妙用
    1、聊一聊首先跟大家推荐一首非常温柔的歌曲,跑步的常听。本文主要把自己对C语言中柔性数组、零数组等等的理解分享给大家,并聊聊如何构建一种统一化的学习思想 ... [详细]
  • 通过将常用的外部命令集成到VSCode中,可以提高开发效率。本文介绍如何在VSCode中配置和使用自定义的外部命令,从而简化命令执行过程。 ... [详细]
  • 本文详细介绍了Java反射机制的基本概念、获取Class对象的方法、反射的主要功能及其在实际开发中的应用。通过具体示例,帮助读者更好地理解和使用Java反射。 ... [详细]
  • 探讨异步 Rust 中多线程代码无法实现并行化的原因及解决方案。 ... [详细]
  • C语言中全部可用的数学函数有哪些?2.longlabs(longn);求长整型数的绝对值。3.doublefabs(doublex);求实数的绝对值。4.doublefloor(d ... [详细]
author-avatar
最好的骨头518_822
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有