为什么需要宏函数
普通泛型函数的局限
普通函数(fun)的参数在调用时先求值,再传入函数体。对于「希望把一段尚未执行的代码交给 callee」这类需求——例如「仅当 Option 为 some 时才执行某段逻辑」——若只用普通函数,往往要:
- 先拆
Option、再手写分支;或 - 传入闭包替代品(Move 没有真正的闭包类型),表达力受限。
宏函数的设计目标之一,就是在保持类型检查的前提下,让你用lambda 参数把代码块传给宏,由宏在展开时按需嵌入这些代码。
宏能做什么(心智模型)
- 代码复用与可读性:标准库用宏封装「遍历向量」「折叠」「重复 n 次」等模式,避免重复的
while与下标管理。 - 零运行时开销:展开结果是普通 Move 代码,不引入额外的函数指针或堆分配(与「在链上解释执行宏」无关——宏根本不存在于字节码中)。
- 惰性:宏参数以语法树片段形式参与展开,是否执行某段代码可以由展开后的控制流决定(例如
option::do!仅在some时进入 lambda)。
宏不是什么
- 不是运行时反射或
eval:没有「链上执行宏」这回事。 - 不是 C 预处理器的文本粘贴:Move 宏在类型系统与合法性检查之下展开,仍有完整语义约束。
- 不能替代所有设计:复杂业务仍应拆成清晰的
fun与数据结构;宏适合重复出现的语法模式与库级抽象。
小结
当你发现自己在多处手写相同形状的 while (i < len) { ... },或反复写「若为 some 则取出再处理」时,优先考虑标准库宏或自定义 macro fun。下一节从编译管线角度说明「编译期」指哪一阶段,以及宏在哪一步介入。