如何创建类似函数的程序宏?

She*_*ter 6 rust rust-macros rust-proc-macros

应该如何a_proc_macro定义以便它“返回”一个 5?

fn main() {
    let a = a_proc_macro!();
    assert!(a == 5);
}
Run Code Online (Sandbox Code Playgroud)

She*_*ter 5

阅读Rust 编程语言关于章节说:

类函数宏定义了看起来像函数调用的宏。与macro_rules!宏类似 ,它们比函数更灵活;例如,它们可以采用未知数量的参数。但是,macro_rules!宏只能使用我们在 前面“用于通用元编程的声明性宏”macro_rules!一节中讨论的类似匹配的语法来定义 。类函数宏接受一个TokenStream参数,它们的定义TokenStream像其他两种类型的过程宏一样使用 Rust 代码来操作它。一个类似函数的宏的例子是一个sql! 可以像这样调用的宏:

let sql = sql!(SELECT * FROM posts WHERE id=1);
Run Code Online (Sandbox Code Playgroud)

这个宏会解析其中的 SQL 语句并检查它的语法是否正确,这比macro_rules!宏可以做的处理复杂得多 。该sql!宏将被定义如下:

#[proc_macro]
pub fn sql(input: TokenStream) -> TokenStream {
Run Code Online (Sandbox Code Playgroud)

这个定义类似于自定义派生宏的签名:我们接收括号内的标记并返回我们想要生成的代码。


Rust 1.45 开始,您可以调用类似函数的过程宏作为表达式。

let sql = sql!(SELECT * FROM posts WHERE id=1);
Run Code Online (Sandbox Code Playgroud)

Cargo.toml

[package]
name = "example"
version = "0.1.0"
edition = "2018"

[dependencies]
example-macro = { path = "example-macro" }
Run Code Online (Sandbox Code Playgroud)

src/main.rs

fn main() {
    assert_eq!(example_macro::a_proc_macro!(), 5);
}
Run Code Online (Sandbox Code Playgroud)

示例宏/Cargo.toml

[package]
name = "example-macro"
version = "0.1.0"
edition = "2018"

[lib]
proc-macro = true
Run Code Online (Sandbox Code Playgroud)

示例宏/src/lib.rs

extern crate proc_macro;

use proc_macro::TokenStream;

#[proc_macro]
pub fn a_proc_macro(_input: TokenStream) -> TokenStream {
    "5".parse().unwrap()
}
Run Code Online (Sandbox Code Playgroud)

也可以看看: