4

手続き型マクロを作成していて、非常に長い識別子を複数回発行する必要があります (たとえば、衛生上の理由による可能性があります)。以前は sをquote!作成してTokenStreamいましたが、長い識別子を何度も繰り返したくありません。

たとえば、次のコードを生成したいとします。

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())、これはかなり面倒です。呼び出しに書きたいだけです#IDENTquote!どうにかして機能させることはできますか?

4

1 に答える 1

7

幸いなことに、方法があります!

#inを介した補間は、traitquote!を介して機能します。その特性を実装するものはすべて補間できます。したがって、定数に構築でき、実装する型を作成するだけです。この特性は、標準の型ではなく の型を使用します。ToTokensToTokensproc-macro2proc-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! {
    let #IDENT = 3;
}

(完全な例)

于 2020-01-06T21:31:18.243 に答える