毫无疑问,宏是rust中极其重要的存在,只要我们看看一些标准库的代码。本文阐述rust宏相关的若干问题
一、宏的定义和作用
先介绍下宏的起源和历史,以便读者更能体会。
以下内容来自文心一言生成:
词源与早期含义
- 希腊-拉丁词根
- "macro"源于希腊语前缀μακρο-(makro-),意为“大”或“长”。拉丁语继承为macro-(如macro-instruction),保留“大”的核心含义。
- 在英语中,"macro"作为形容词表示“巨大的”(如macroeconomic),作为名词则特指计算机领域的“宏指令”。
- 早期通用含义
- 在非技术领域,"macro"常用于描述大规模事物(如macro-scale planning),与“微观”(micro)形成尺度对比。
计算机领域的起源与演变
- 20世纪50年代:汇编语言的宏指令
- 背景:早期计算机编程依赖汇编语言,重复性任务(如寄存器操作)导致代码冗长。
- 突破:IBM 705计算机(为陶氏化学公司开发)首次引入宏指令(macro-instruction),允许用简短符号代替复杂指令序列。
- 1960年代:LISP语言的元编程宏
- 关键人物:Timothy Hart在1963年提出在LISP 1.5中添加宏,通过宏编译器将高阶语法转换为底层代码。
- 意义:宏成为编程语言扩展机制,支持用户自定义语法(如定义领域专用语言DSL)。
- 1990年代:VBA与办公自动化
- 转折点:微软在Office套件中集成VBA(Visual Basic for Applications),使宏进入大众视野。
- 应用爆发:用户可通过录制宏自动化Excel公式计算、Word文档排版等操作,显著提升办公效率。
基本没有什么毛病!
概括下:
1.macro(宏)-起源于希腊,后拉丁借用,最后是英语用上了。
2.macro的核心意思就是:巨大,宏观(大规模现象之意)
3.在计算机领域,大体保留了对macro的含义,例如宏病毒,宏指令
具体到计算机,可以这样理解:宏或者宏指令就是表达了一大段代码的对象(命令/指令等),表达了有许多代码的意思。
这是一个习惯问题。只要愿意,我们也可以称为:多指令集合,多代码集合。
所以,总结起来,rust宏定义:用于表示一段代码或者条件语句,其构成可能是一段代码,或则可能也没有任何代码。
或者说宏的核心作用就是两个
1.条件编译
2.表示一段代码,有助于简化编程
从这里可以看出rust宏和C++宏的作用极其相似!
二、宏实现原理
从其自用可以看出,其实现原理相当简单:
1.如果是条件编译指令,那么编译器发现后当做条件执行
2.如果表示一段代码,则rust编译器会把指令替换为一段代码(大体是提单,但具体上应该还是有一些额外的内容)
宏都是在编译的时候起到作用!
三、宏和函数区别
书籍作者为什么要提到这个? 开始的时候我不太明白,直到我看了宏的代码。
宏的代码看起来有点像函数。
这里先总结下rust中宏和函数的区别:
1.宏可不仅仅是一段代码,还可以作为编译条件
2.宏可以接收不同个数参数(或者说不定个数参数),而函数不能
3.宏是在编译环节起作用(编译器会根据宏类型来决定作为编译条件还是实现一段代码),而函数是在运行时起到作用
四、标准宏
4.1、常见标准宏
表_常见标准宏
[table][tr]宏名称功能描述所属模块/类型[/tr][tr][td]assert![/td][td]断言表达式为 true,否则触发 panic(常用于单元测试)[/td][td]标准库(测试相关)[/td][/tr][tr][td]assert_eq![/td][td]断言两个值相等,否则触发 panic[/td][td]标准库(测试相关)[/td][/tr][tr][td]assert_ne![/td][td]断言两个值不相等,否则触发 panic[/td][td]标准库(测试相关)[/td][/tr][tr][td]compile_error![/td][td]在编译期生成错误(用于自定义编译时检查)[/td][td]标准库(元编程)[/td][/tr][tr][td]concat![/td][td]连接多个字面量,返回 &'static str[/td][td]标准库(字符串操作)[/td][/tr][tr][td]column![/td][td]返回当前源代码的列号[/td][td]标准库(调试信息)[/td][/tr][tr][td]dbg![/td][td]输出表达式的值和类型(调试工具)[/td][td]标准库(调试相关)[/td][/tr][tr][td]eprint![/td][td]输出到标准错误流(不换行)[/td][td]标准库(I/O 操作)[/td][/tr][tr][td]eprintln![/td][td]输出到标准错误流(自动换行)[/td][td]标准库(I/O 操作)[/td][/tr][tr][td]env![/td][td]获取编译期环境变量(若变量不存在则报错)[/td][td]标准库(环境变量)[/td][/tr][tr][td]file![/td][td]返回当前源代码的文件名[/td][td]标准库(调试信息)[/td][/tr][tr][td]format![/td][td]格式化字符串并返回 String[/td][td]标准库(字符串操作)[/td][/tr][tr][td]include_bytes![/td][td]将文件读取为字节数组(&'static [u8])[/td][td]标准库(文件操作)[/td][/tr][tr][td]include_str![/td][td]将文件读取为字符串(&'static str)[/td][td]标准库(文件操作)[/td][/tr][tr][td]line![/td][td]返回当前源代码的行号[/td][td]标准库(调试信息)[/td][/tr][tr][td]macro_rules![/td][td]定义声明式宏(如 vec!)[/td][td]标准库(宏定义)[/td][/tr][tr][td]module_path![/td][td]返回当前模块的路径[/td][td]标准库(调试信息)[/td][/tr][tr][td]option_env![/td][td]安全获取编译期环境变量(返回 Option |