[英]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.