如何创建 proc_macro_attribute?
Posted
技术标签:
【中文标题】如何创建 proc_macro_attribute?【英文标题】:How do I create a proc_macro_attribute? 【发布时间】:2019-03-06 05:52:55 【问题描述】:既然proc_macros
have been stabilized,怎么会创造出这样的东西?
据我所知,可以选择在fn whatsitsname(attrs: TokenStream, code: TokenStream) -> TokenStream
上添加#[proc_macro_attribute]
注释,但我该如何注册呢?如何添加自定义属性?
【问题讨论】:
对于它的价值,这本书包含一个section on writing procedural macros。 @SvenMarnach 这仅解释了proc_macro_derive
,而不是proc_macro_attribute
。
@lllogiq 我知道这一点,但是该链接可能对登陆这里的其他人有用。 (你的第一个问题是“如何创造这样的东西”,这已经涵盖了。)
我会说它们应该记录在由@SvenMarnach 链接的书籍附录中,如果没有,这是一个应该报告的错误并在跟踪中引用问题github.com/rust-lang/rust/issues/38356(它仍然是开放的,并没有提到记录该功能,但可能应该)。
【参考方案1】:
Rust 编译器有一个相当完整的test suite。在寻找新引入功能的示例时,我经常从那里开始:
$ rg -c proc_macro_attribute
src/test/run-pass-fulldeps/auxiliary/proc_macro_def.rs:2
src/test/ui-fulldeps/auxiliary/attr_proc_macro.rs:1
[... 35 other matches ...]
这是一个完整的例子:
$ tree
.
├── Cargo.toml
├── my_macro
│ ├── Cargo.toml
│ ├── src
│ │ └── lib.rs
└── src
└── main.rs
Cargo.toml
我们添加了对宏定义 crate 的依赖。
[package]
name = "foo"
version = "0.1.0"
authors = ["An Devloper <an.devloper@example.com>"]
[dependencies]
my_macro = path = "my_macro"
src/main.rs
我们导入属性宏并将其添加到函数中。
#[macro_use]
extern crate my_macro;
#[log_entry_and_exit(hello, "world")]
fn this_will_be_destroyed() -> i32
42
fn main()
dummy()
my_macro/Cargo.toml
我们将crate_type
指定为proc_macro
。
[package]
name = "my_macro"
version = "0.1.0"
authors = ["An Devloper <an.devloper@example.com>"]
[lib]
crate_type = ["proc-macro"]
my_macro/src/lib.rs
我们将#[proc_macro_attribute]
添加到每个应该是宏的函数中。
extern crate proc_macro;
use proc_macro::*;
#[proc_macro_attribute]
pub fn log_entry_and_exit(args: TokenStream, input: TokenStream) -> TokenStream
let x = format!(r#"
fn dummy()
println!("entering");
println!("args tokens: ", args);
println!("input tokens: ", input);
println!("exiting");
"#,
args = args.into_iter().count(),
input = input.into_iter().count(),
);
x.parse().expect("Generated invalid tokens")
货物运行
entering
args tokens: 3
input tokens: 7
exiting
“困难”部分是将TokenStream
变成有用的东西,然后输出同样有用的东西。板条箱syn 和quote 是这两项任务的当前黄金标准。处理TokenStream
包含在macros chapter of The Rust Programming Language 和API documentation 中。
还有#[proc_macro]
,它的函数形式如下:
#[proc_macro]
pub fn the_name_of_the_macro(input: TokenStream) -> TokenStream
并且可以调用为the_name_of_the_macro!(...)
。
【讨论】:
【参考方案2】:如果我对RFC 1566 的理解正确,您:
创建一个 proc_macro
类型的 crate,即它的 Cargo.toml
应该包含
[lib]
proc-macro = true
在那个 crate 中,创建实现,用 #[proc_macro_attribute]
注释。类似函数的宏的#[proc_macro]
和自定义派生的#[proc_macro_derive]
的工作方式相同,只是它们只有一个TokenStream
参数。这些在proc_macro
crate 中定义。
第一个标记流是属性中的参数,第二个是注释项的主体。
然后在要使用宏的 crate 中,只需依赖 proc_macro crate 和
使用 #[macro_use]
属性 (#[macro_use] extern crate
...) 导入它。
应该够了。
appendix in Book 应该被扩展以提及除#[proc_macro_derive]
之外的其他 proc 宏类型。它没有可能是一个错误。
【讨论】:
以上是关于如何创建 proc_macro_attribute?的主要内容,如果未能解决你的问题,请参考以下文章