元编程
元编程
元编程可以理解为“编写能生成代码的代码”。
在 C#/.NET 中,Roslyn 从 .NET 5 开始提供了 Source Generators。
它可以在构建期生成新的 C# 源文件,并并入当前编译。
在 Source Generators 之前,Visual Studio 也常用 T4 Text Templates
做代码生成,可参考这个 template 与其 concretization。
Rust 也提供元编程能力:宏(macros)。主要分为 declarative macros
和 procedural macros。
声明式宏(declarative macros)通过模式匹配输入语法并展开对应代码。
下面是 println! 的定义片段(调用形式如 println!("Some text")):
macro_rules! println {
() => {
$crate::print!("\n")
};
($($arg:tt)*) => {{
$crate::io::_print($crate::format_args_nl!($($arg)*));
}};
}想深入声明式宏,可阅读 macros by example 与 The Little Book of Rust Macros。
Procedural macros 与声明式宏不同:它接收代码作为输入,对其处理后再产出代码。
C# 元编程里另一个常见手段是反射;Rust 标准语言层面不提供对应的运行时反射体系。
函数式宏
函数式宏(function-like macro)形如:name!(...)。
下面示例定义了名为 print_something 的函数式宏,它会生成 print_it 方法并打印
"Something"。
在 lib.rs:
extern crate proc_macro;
use proc_macro::TokenStream;
#[proc_macro]
pub fn print_something(_item: TokenStream) -> TokenStream {
"fn print_it() { println!(\"Something\") }".parse().unwrap()
}在 main.rs:
use replace_crate_name_here::print_something;
print_something!();
fn main() {
print_it();
}派生宏
派生宏(derive macro)可基于结构体/枚举/联合体的 token stream 生成新代码。
最常见示例是 #[derive(Clone)],它会为目标类型自动生成 Clone trait 实现。
自定义派生宏可参考 Rust Reference 的 derive macros。
属性宏
属性宏(attribute macro)用于定义可挂载在 Rust 条目上的新属性。
例如在 Tokio 异步程序中,通常会先使用 #[tokio::main]:
#[tokio::main]
async fn main() {
println!("Hello world");
}自定义属性宏可参考 attribute macros。