Elixir - プライベート関数を動的に呼び出す 質問する

Elixir - プライベート関数を動的に呼び出す 質問する

Kernel.apply/3メソッドをアトムとして指定することで、モジュール内のパブリックメソッドを動的に呼び出すことができる方法を見つけました。たとえば、次result = apply(__MODULE__, :my_method, [arg])のように変換されます。result = my_method(arg)

私を困惑させるのは、プライベート メソッドを呼び出す方法です。次のようなコードがあるとします。

defmodule MyModule do
    def do_priv(atom, args) when is_list(args) do
        apply(__MODULE__, atom, args)
    end

    # (change defp => def, and this all works)
    defp something_private(arg), do: arg #or whatever
end

これはモジュール内からのプライベート メソッドの呼び出しなので、許容されると思いますMyModule.do_priv(:something_private, [1])。Elixir は内部的に Erlang の apply/3 を使用しているため、このアプローチではおそらく目的を達成できないと思います。

私もこのCode.eval_quoted/3メソッドを使ってみましたが、ハードコードされたプライベート メソッドを呼び出すことすらできないようです (したがって、quote do以下のように使用するのではなく、手動で AST を構築するのに時間がかかりません。ただし、誰かがこれを機能させる方法を知っている場合は、それがオプションになります)。

defmodule MyModule do
    def do_priv_static do
        something_private(1) #this works just fine
    end

    def do_priv_dynamic do
        code = quote do
            something_private(1)
        end
        Code.eval_quoted(code, [], __ENV__)   #nope.  fails
    end

    defp something_private(arg), do: arg #or whatever
end

繰り返しますが、これは包含モジュール内からのプライベート関数へのアクセスなので、許可されるはずです。私がパラメータを理解していないだけかもしれません__ENV__eval_quoted

現時点で機能する唯一の解決策defpは に変更することですdef。これは私の個人的なコードには適した解決策ですが、私は気にかける他のプログラマーをサポートするコードを書いているので、解決策を見つけたいと思います。

他のアプローチも検討しますが、個人的にはこれを実現する方法がわかりません。

ベストアンサー1

まず、f()MyModuleモジュール内で呼び出されることはMyModule.f()、同じ場所で呼び出されることと同じではないことを知っておく必要があります。http://www.erlang.org/doc/reference_manual/code_loading.html#id86422

プライベート関数のみのf()スタイルで呼び出すことができます。これらの呼び出しもコンパイラによってチェックされます。関数が存在しない場合はコンパイルエラーになります。MyModule.f()同じ場所で使用する場合は、ないこれらの呼び出しは実行時にのみチェックされるため (モジュールをその内部から呼び出している場合でも)、コンパイル エラーが発生します。その効果は (私の知る限り)MyModule.f()他のモジュールから呼び出した場合と同じです。モジュールは実行時に検索され、エクスポートされた (パブリック) 関数のみを呼び出すことができます。

したがって、ない単なるf().以外の方法でプライベート関数を呼び出すことは、スタイルapply(mod,fun,[])と同等です。mod.fun.()モジュールは実行時に解決され、プライベート関数にはアクセスできません。

この例では、すべてのバリエーションを自分で試すことができます。https://gist.github.com/mprymek/3302ff9d13fb014b921b

プライベート関数の呼び出しはコンパイル時に常に認識される必要があるため、eval_quoted マジックやその他のマジックを使用しても、それらを「動的」にすることはできないことがわかります...

Sasa Juric 氏のアドバイスは@doc false正しい解決策です。

おすすめ記事