应该如何a_proc_macro
定义它“返回”一个 5?
fn main() {
let a = a_proc_macro!();
assert!(a == 5);
}
应该如何a_proc_macro
定义它“返回”一个 5?
fn main() {
let a = a_proc_macro!();
assert!(a == 5);
}
阅读Rust 编程语言关于宏的章节说:
类函数宏定义看起来像函数调用的宏。与宏类似
macro_rules!
,它们比函数更灵活;例如,它们可以采用未知数量的参数。但是,只能使用我们在前面“用于通用元编程的声明性宏”</a>macro_rules!
部分中讨论的类似匹配的语法来定义 宏。类函数宏接受一个参数,并且它们的定义使用 Rust 代码来操作,就像其他两种类型的过程宏一样。类似函数的宏的一个示例是 可以这样调用的宏:macro_rules!
TokenStream
TokenStream
sql!
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()
}
也可以看看:
在稳定的 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"
到依赖项部分;#[proc_macro_hack] use example_macro::a_proc_macro;
in ,并从本地命名空间src/main.rs
调用。a_proc_macro!
#[proc_macro_hack::proc_macro_hack]
的定义之前添加。a_proc_macro
example-macro/src/lib.rs