[英]How can I compute an instance of a type in a function-like procedural macro and return it?
我有Foo
类型:
pub struct Foo { ... }
现在我想创建一个过程宏来创建这个结构的一个实例。 这可能涉及繁重的计算、文件访问或其他只有过程宏才能做的事情,但如何创建该实例的确切细节在这里并不重要。
我这样定义我的程序宏:
#[proc_macro]
pub fn create_foo(_: TokenStream) -> TokenStream {
let foo_value: Foo = /* some complex computation */;
// TODO: return `foo_value`
}
我的程序宏的用户应该能够这样写:
fn main() {
let a: Foo = create_foo!();
}
请注意, Foo
可能包含大量数据,例如数兆字节的Vec
数据。
如何从我的程序宏中返回Foo
值?
虽然这似乎是一个简单的请求,但实际上有很多事情要展开。
最重要的是,了解过程宏只返回令牌(即 Rust 代码)至关重要。 坦率地说:Rust 编译器执行您的过程宏,获取生成的标记并将它们粘贴到您的过程宏调用所在的用户代码中。 您可以将过程宏视为一个预处理步骤,它将您的 Rust 代码转换为另一个.rs
文件。 然后将该文件提供给编译器。
为了“返回Foo
的值”,您必须返回一个TokenStream
,它代表一个计算结果为Foo
的表达式。 例如:
#[proc_macro]
pub fn create_foo(_: TokenStream) -> TokenStream {
quote! { Foo { data: vec![1, 2, 3] } }
}
在用户的箱子中:
let a: Foo = create_foo!();
这将扩展为:
let a: Foo = Foo { data: vec![1, 2, 3] };
data: vec,[1, 2, 3]
部分可以由过程宏动态生成。 如果您的Foo
实例非常大,则创建该实例的代码也可能非常大。 这意味着编译时间可能会增加,因为 Rust 编译器必须解析和检查这个巨大的表达式。
所以不能直接返回值? 不,你可能认为你可以使用unsafe
的代码来做到这一点。 例如,发出一个大的const DATA: &[u8] =...;
和mem::transmute
它到Foo
,但你不能有几个原因:
Foo
在 memory 中的表示方式。 对于您的程序宏和您的用户 crate,相同的Foo
实例在 memory 中的表示方式可能不同,因此您不能transmute
。Foo
包含堆分配结构( Vec
),你无论如何都不能这样做。如果您必须在程序宏中生成值,那么只有一种解决方案可以将其提供给用户,但这并不是最优的。 或者,也许在运行时计算一次并不是那么糟糕。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.