【发布时间】:2020-03-14 06:26:55
【问题描述】:
应该如何定义a_proc_macro 使其“返回”一个 5?
fn main() {
let a = a_proc_macro!();
assert!(a == 5);
}
【问题讨论】:
标签: rust rust-macros rust-proc-macros
应该如何定义a_proc_macro 使其“返回”一个 5?
fn main() {
let a = a_proc_macro!();
assert!(a == 5);
}
【问题讨论】:
标签: rust rust-macros rust-proc-macros
阅读The Rust Programming Language'smacros 的章节说:
类函数宏定义看起来像函数调用的宏。类似于
macro_rules!宏,它们比函数更灵活;例如,他们 可以接受未知数量的参数。但是,macro_rules!宏可以是 仅使用我们在本节中讨论的类似匹配的语法定义 “Declarative Macros withmacro_rules!for General Metaprogramming” 早些时候。类函数宏采用TokenStream参数及其 定义使用 Rust 代码作为另外两个来操纵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
Cargo.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);
}
example-macro/Cargo.toml
[package]
name = "example-macro"
version = "0.1.0"
edition = "2018"
[lib]
proc-macro = true
example-macro/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's answer 会告诉您如何使用。
如果您处于稳定状态,您仍然可以模拟类似表达式的过程宏,如下所示:
在您的情况下,您可以像这样定义程序宏:
#[proc_macro]
pub fn a_proc_macro_impl(_input: TokenStream) -> TokenStream {
"fn output() -> usize { 5 }".parse().unwrap()
}
...helper 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 crate 的帮助下,您可以在稳定版上运行 Shepmaster 的答案中几乎未更改的代码:
Cargo.toml 文件并将proc-macro-hack = "0.5.11" 添加到依赖项部分;src/main.rs 中添加#[proc_macro_hack] use example_macro::a_proc_macro;,并从本地命名空间调用a_proc_macro!。example-macro/src/lib.rs中a_proc_macro的定义前添加#[proc_macro_hack::proc_macro_hack]。【讨论】: