函数式过程宏能在编译期运行任意 Rust 代码:算常量、解析自定义语法、读文件。但它也有陷阱:cargo 不知道宏读过什么文件。这篇三种用法都真实跑通,并复现了那个「改了文件却没生效」的坑。
运行: fib!(30) = 832040 fib!(10) = 55
展开后的 main:
fn main() {
const F30: u64 = 832040u64;
{
::std::io::_print(format_args!("fib!(30) = {0} fib!(10) = {1}\n",
F30, 55u64));
};
}过程宏的阶段见过程宏的执行阶段。
编译退出码 0
运行:
[("a", 1), ("b", 5), ("c", 4)]
空: 0声明宏版本的写法见声明宏 macro_rules!。
build 后运行: 版本 = "1.0" 把 version.txt 改成 2.0 后 cargo build 输出: ['Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.01s'] 运行: 版本 = "1.0" ← 仍是旧值(宏没有重新运行) 改动 main.rs(加一个换行)再 build 后运行: 版本 = "2.0"
error: 读取 不存在.txt 失败: No such file or directory (os error 2)
--> src/main.rs:3:28
|
3 | fn main() { let _ = embed!("不存在.txt"); let _ = fib!(99999999999); let _ = fib!("x"); }
| ^^^^^^^^^^^^
error: number too large to fit in target type
--> src/main.rs:3:53
|
3 | fn main() { let _ = embed!("不存在.txt"); let _ = fib!(99999999999); let _ = fib!("x"); }
| ^^^^^^^^^^^
error: expected integer literal
--> src/main.rs:3:80
|
3 | fn main() { let _ = embed!("不存在.txt"); let _ = fib!(99999999999); let _ = fib!("x"); }
| ^^^
error: could not compile `app` (bin "app") due to 3 previous errorsbuild 后运行: include_str 版本 = "3.0" 改文件为 4.0 后 cargo build: ['Compiling app v0.1.0 (<实验目录>/proj/u82/app)', 'Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.12s'] 运行: include_str 版本 = "4.0" ← 新值,cargo 追踪了 include_str! 读的文件
想让自定义宏也在文件改动时重编译,可以尝试 build.rs 的 cargo:rerun-if-changed(见 Build Script build.rs),这一点没有验证。