8

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

fn main() {
    let a = a_proc_macro!();
    assert!(a == 5);
}
4

2 回答 2

6

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

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

let sql = sql!(SELECT * FROM posts WHERE id=1);

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

#[proc_macro]
pub fn sql(input: TokenStream) -> TokenStream {

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


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

example
├── Cargo.toml
├── example-macro
│   ├── Cargo.toml
│   ├── src
│   │   └── lib.rs
├── src
│   └── main.rs

货运.toml

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

[dependencies]
example-macro = { path = "example-macro" }

src/main.rs

fn main() {
    assert_eq!(example_macro::a_proc_macro!(), 5);
}

示例宏/Cargo.toml

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

[lib]
proc-macro = true

示例宏/src/lib.rs

extern crate proc_macro;

use proc_macro::TokenStream;

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

也可以看看:

于 2019-11-18T20:06:28.247 回答
1

在稳定的 Rust 中,直接定义类似表达式的过程宏是不可能的。如果您可以每晚使用,Shepmaster 的回答显示了如何使用。

如果您处于稳定状态,您仍然可以模拟类似表达式的过程宏,如下所示:

  • 定义一个过程宏,该宏扩展为一个函数,该函数的计算结果为您要调用的表达式;
  • 然后定义一个常规宏,该宏扩展为嵌入函数定义和调用的块。

在您的情况下,您将像这样定义程序宏:

#[proc_macro]
pub fn a_proc_macro_impl(_input: TokenStream) -> TokenStream {
    "fn output() -> usize { 5 }".parse().unwrap()
}

...辅助macro_rules!宏遵循以下模式:

macro_rules! a_proc_macro {
    ($($t:tt)*) => {{
        struct _X;
        impl _X {
            a_proc_macro!($($t)*);
        }
        _X::output()
    }}
}

这是一个 hack,而且很麻烦,但是proc-macro-hack crate 来拯救它,它可以更容易地使用上述技术生成过程宏。在proc-macro-hack板条箱的帮助下,您可以运行 Shepmaster 对 stable 的回答中几乎未更改的代码:

  • 编辑这两个Cargo.toml文件并添加proc-macro-hack = "0.5.11"到依赖项部分;
  • add #[proc_macro_hack] use example_macro::a_proc_macro;in ,并从本地命名空间src/main.rs调用。a_proc_macro!
  • 在in#[proc_macro_hack::proc_macro_hack]的定义之前添加。a_proc_macroexample-macro/src/lib.rs
于 2019-11-18T20:48:45.510 回答