簡體   English   中英

如何將標識符 (`proc_macro::Ident`) 存儲為常量以避免重復?

[英]How can I store an identifier (`proc_macro::Ident`) as a constant to avoid repeating it?

我正在編寫一個程序宏,我需要多次發出一個很長的標識符(可能是因為衛生,例如)。 我用quote! 創建TokenStream s,但我不想一遍又一遍地重復長標識符!

例如,我想生成此代碼:

let very_long_ident_is_very_long_indeed = 3;
println!("{}", very_long_ident_is_very_long_indeed);
println!("twice: {}", very_long_ident_is_very_long_indeed + very_long_ident_is_very_long_indeed);

我知道我可以創建一個Ident並將其插入quote!

let my_ident = Ident::new("very_long_ident_is_very_long_indeed", Span::call_site());
quote! {
    let #my_ident = 3;
    println!("{}", #my_ident);
    println!("twice: {}", #my_ident + #my_ident);
}

到目前為止一切順利,但我需要在我的代碼庫中的許多函數中使用該標識符。 我希望它是一個可以在任何地方使用的const 但是,這失敗了:

const FOO: Ident = Ident::new("very_long_ident_is_very_long_indeed", Span::call_site());

出現此錯誤:

error[E0015]: calls in constants are limited to constant functions, tuple structs and tuple variants
 --> src/lib.rs:5:70
  |
5 | const FOO: Ident = Ident::new("very_long_ident_is_very_long_indeed", Span::call_site());
  |                                                                      ^^^^^^^^^^^^^^^^^

error[E0015]: calls in constants are limited to constant functions, tuple structs and tuple variants
 --> src/lib.rs:5:20
  |
5 | const FOO: Ident = Ident::new("very_long_ident_is_very_long_indeed", Span::call_site());
  |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

我懷疑這些函數是否會很快被標記為const

我可以使字符串本身成為一個常量:

const IDENT: &str = "very_long_ident_is_very_long_indeed";

但是無論我想在哪里使用標識符,我都需要調用Ident::new(IDENT, Span::call_site()) ,這會很煩人。 我只想在我的quote!寫上#IDENT quote! 調用。 我能以某種方式使它工作嗎?

幸運的是,有辦法!

通過quote! #進行插值quote! 通過ToTokens trait 工作 實現該特性的所有內容都可以插入。 所以我們只需要創建一個可以構造為常量並實現ToTokens 該特征使用來自proc-macro2類型而不是標准的proc-macro

use proc_macro2::{Ident, Span, TokenStream};


struct IdentHelper(&'static str);

impl quote::ToTokens for IdentHelper {
    fn to_tokens(&self, tokens: &mut TokenStream) {
        Ident::new(self.0, Span::call_site()).to_tokens(tokens)
    }
}

現在您可以定義您的標識符:

const IDENT: IdentHelper = IdentHelper("very_long_ident_is_very_long_indeed");

並直接在quote!使用它quote!

quote! {
    let #IDENT = 3;
}

完整示例

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM