0

私はmacro_rulesを取り、function_nameを呼び出すを持っていますfunction_name_x()function_name現在、として渡しident、 を介して新しい関数名を作成することでそれを行っていconcat_idents!ます。

このアプローチの問題は、IDE がfunction_nameパーツを lint しないことidentです。に変更したいのですが、そうするとty使えませんconcat_idents!

解決策はありますか?

macro_rules! decl_func {
    ($env:expr, $func:ident) => {{
        let f = concat_idents!($func, _to_ocaml);
        let binding = f($env, None);
        println!("{}", binding);
    }};
}
4

1 に答える 1

1

あなたの使い方から判断するとident、正しい選択だと思います。path、 、などの他のものはttexpr一般的に関数を受け入れるのに適しているかもしれませんが、それを使用して別の識別​​子を作成するだけなidentので、最も理にかなっています。


洗練されたモンテカルロ分析によって、rust-analyzer はマクロの構文検出を最初に展開し、生成されたコードを評価し、その情報を元のマクロ パラメータに逆参照することで処理しているようです。

次の例では、呼び出しは識別子を関数定義にdecl_func1正しくリンクしていますが、呼び出しはリンクしていません。function_namedecl_func2

fn function_name() {}

macro_rules! decl_func1 {
    ($func:ident) => {
        $func();
    };
}

macro_rules! decl_func2 {
    ($func:ident) => {};
}

fn main() {
    decl_func1!(function_name);
    decl_func2!(function_name);
}

したがって、コードではfunction_name、生成されたコードにはfunction_name_x.


潜在的な回避策は、識別子をそのまま構文的に使用するステートメントをマクロに導入することですが、最終的には何もしません。とにかく、rust-analyzer だけでなく、コンパイラが識別子が本来あるべきものであることを確認できるようにするために、これは良い考えかもしれません。いくつかのアイデア:

// would check that it is some kind of value
let _ = &$func;
// would check that it is a function with a signature that can take these types
let _ = || $func(1, 2);
于 2021-10-02T06:58:54.263 に答える