太原市网站建设_网站建设公司_无障碍设计_seo优化
2025/12/21 10:37:13 网站建设 项目流程

Rust 的宏(macro) 是一种在编译期进行代码生成或转换的机制,它允许你编写“生成代码的代码”,从而减少重复、提升表达力,并实现一些普通函数无法做到的功能(比如定义 DSL、处理可变参数等)。

与函数不同,宏在编译阶段展开,不产生运行时开销(零成本抽象)。


一、宏的类型

Rust 主要有两类宏:

类型 说明 语法
声明宏(Declarative Macros) 类似“模板匹配”,通过模式匹配生成代码 macro_rules!
过程宏(Procedural Macros) 用 Rust 代码操作 AST,功能更强(如 #[derive(...)] #[proc_macro], #[proc_macro_attribute], #[proc_macro_derive]

本回答重点介绍声明宏标准库中的预定义宏(因过程宏较复杂,常用于高级场景)。


二、什么是 macro_rules! 宏?(声明宏)

基本语法

macro_rules! 宏名 {(模式) => { 生成的代码 };(另一个模式) => { 另一段代码 };
}

示例:自定义宏

macro_rules! say_hello {() => {println!("Hello!");};($name:expr) => {println!("Hello, {}!", $name);};
}fn main() {say_hello!();           // → Hello!say_hello!("Alice");    // → Hello, Alice!
}

✅ 宏调用以 ! 结尾(如 println!),这是 Rust 识别宏的方式。


三、标准库中的常用预定义宏(无需导入,自动可用)

以下是 Rust 标准库(std 提供的、最常用且预定义的宏(部分需 use,但多数在 prelude 中):


1. println! / print!

作用:格式化输出到 stdout。

println!("Hello, {}!", "world");
println!("{name} is {age} years old", name = "Alice", age = 30);

2. format!

作用:格式化生成 String(不打印)。

let s = format!("Hello, {}!", "Rust");
// s: String = "Hello, Rust!"

3. vec!

作用:创建 Vec<T>

let v1 = vec![1, 2, 3];
let v2 = vec![0; 5]; // [0, 0, 0, 0, 0]

4. assert! / assert_eq! / assert_ne!

作用:调试断言,失败时 panic。

assert!(x > 0);
assert_eq!(a, b);   // 如果 a != b,panic 并显示差异
assert_ne!(a, b);   // 如果 a == b,panic

5. panic!

作用:主动触发 panic。

panic!("Something went wrong!");

6. dbg!

作用:调试打印表达式的值和位置(返回原值)。

let x = dbg!(2 + 3); // 输出:[src/main.rs:2] 2 + 3 = 5

7. todo! / unimplemented!

作用:占位符,表示“尚未实现”,调用时 panic。

fn new_feature() -> String {todo!("Implement this later")
}

8. include_str! / include_bytes!

作用:在编译期将文件内容嵌入代码。

let txt = include_str!("config.txt");   // &str
let bin = include_bytes!("data.bin");   // &[u8]

✅ 文件路径相对于源文件所在目录。


9. concat! / env! / file! / line!

作用:编译期常量操作。

let msg = concat!("Hello", " ", "World"); // "Hello World"
let rustc = env!("RUSTC");                // 编译器路径
println!("File: {}, Line: {}", file!(), line!());

10. write! / writeln!

作用:向实现了 std::fmt::Write 的对象写入格式化内容(如 String、文件)。

use std::fmt::Write;
let mut output = String::new();
writeln!(&mut output, "Result: {}", 42).unwrap();

四、宏 vs 函数 的关键区别

特性 函数
调用语法 name!(...) name(...)
参数数量 可变(如 println!("", a, b, c) 固定
类型检查时机 展开后才类型检查 调用时立即检查
能力 可生成任意代码(如定义新变量、结构体) 只能执行逻辑
性能 零成本(编译期展开) 有函数调用开销(可能被内联)

五、总结

  • 宏是 Rust 的“编译期代码生成器”,强大且零成本。
  • 标准库提供了大量实用宏,覆盖 I/O、断言、调试、初始化等场景。
  • 调用宏必须加 !,这是识别宏的关键。
  • 优先使用标准宏(如 vec!, format!),它们安全、高效、惯用。
  • 自定义宏适用于消除重复代码或构建 DSL,但应谨慎使用(可读性可能降低)。

💡 记住
你每天写的 println!, vec!, assert_eq! 都是宏——它们让 Rust 既安全又富有表现力。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询