Elixir - 动态调用私有(private)函数

标签 elixir

我找到了Kernel.apply/3它允许通过将方法指定为原子来动态调用模块中的公共(public)方法,例如result = apply(__MODULE__, :my_method, [arg])转换为 result = my_method(arg)
让我感到困惑的是调用私有(private)方法的方式;给定这样的代码:

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])是允许的,因为它是从模块内调用私有(private)方法。我可以理解 Elixir 在底层使用 Erlang 的 apply/3,所以这种方法可能不会让我们到达那里。

我也试过使用 Code.eval_quoted/3方法,但它似乎甚至不能调用硬编码的私有(private)方法(因此没有时间花在手动构建 AST 上,而不是使用 quote do 如下 - 尽管如果有人看到如何制作这个选项,这是一个选项工作):
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

同样,它是从包含模块中访问私有(private)函数的,所以我希望它是允许的。可能我只是不明白 __ENV__ eval_quoted 的参数

目前唯一可行的解​​决方案是更改 defpdef ,这是我个人代码的一个很好的解决方案;但由于我编写的代码支持其他关心的程序员,我想找到一个解决方案。

我对其他方法持开放态度,但我个人对如何实现这一点感到困惑。

最佳答案

一开始你应该知道f()在 MyModule 模块中调用与 MyModule.f() 不同。在同一个地方调用。见 http://www.erlang.org/doc/reference_manual/code_loading.html#id86422

您只能调用私有(private)函数 f()风格。编译器也会检查这些调用 - 如果函数不存在,则会出现编译错误。当您使用 MyModule.f()在同一个地方,您不会收到编译错误,因为这些调用仅在运行时检查(即使您从自身内部调用模块)并且效果(AFAIK)与调用 MyModule.f() 相同从任何其他模块 - 在运行时查找该模块,您只能调用导出的(公共(public))函数。

因此,除了简单的 f() 之外,您不能以任何其他方式调用私有(private)函数。 . apply(mod,fun,[])相当于mod.fun.() style - 模块在运行时解析,私有(private)函数不可访问。

在此示例中,您可以自己尝试所有变体:https://gist.github.com/mprymek/3302ff9d13fb014b921b

您现在可以看到,在编译时必须始终知道对私有(private)函数的调用,因此您甚至不能使用 eval_quoted 魔术或任何其他魔术来使它们“动态”...

Sasa Juric 的使用建议 @doc false是正确的解决方案。

关于Elixir - 动态调用私有(private)函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28929866/

相关文章:

authentication - 如何在 Elixir 中的进程之间建立经过身份验证的链接?

elixir - 在由OR连接的where子句中组成具有多个列的Ecto查询

visual-studio-code - 与Phoenix和VSCode一起使用时,ElixirLS调试器意外停止

elixir - get_in 访问行为药剂的可选默认值

Elixir - 尝试/捕获 vs 尝试/救援?

erlang - 为 erlang 寻找持久的、分布式的工作队列

elixir - 加入 Phoenix Channel(或其他 pubsub)时同步应用程序状态

elixir - 如何在我的模型文件中使用 Repo 模块

erlang - 在 Elixir 中,依赖应用程序是否受到监督?

elixir - 什么是 Elixir Plug?