我找到了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
的参数目前唯一可行的解决方案是更改
defp
至def
,这是我个人代码的一个很好的解决方案;但由于我编写的代码支持其他关心的程序员,我想找到一个解决方案。我对其他方法持开放态度,但我个人对如何实现这一点感到困惑。
最佳答案
一开始你应该知道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/