cratosw

元编程

元编程

元编程可以理解为“编写能生成代码的代码”。

在 C#/.NET 中,Roslyn 从 .NET 5 开始提供了 Source Generators。 它可以在构建期生成新的 C# 源文件,并并入当前编译。
在 Source Generators 之前,Visual Studio 也常用 T4 Text Templates 做代码生成,可参考这个 template 与其 concretization

Rust 也提供元编程能力:宏(macros)。主要分为 declarative macrosprocedural 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 exampleThe 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

On this page