Elixir中的动态调度是这样的

问题描述 投票:0回答:1

我想创建一个函数,并将其嵌入到其他模块中。而不需要在这些产品中重新实施。. 会是这样的。

defmodule MyModuleWithFunction do
  def my_function(m) do
    IO.puts("***my name: #{__MODULE__}. My current value: #{m.var1}")
  end
end

# usage 1
defmodule M1 do
  def var1 do
    "M1 var1"
  end

  # somehow embed my_function() here without having to re-implement it
end

# usage 2
defmodule M2 do
  def var1 do
    "M2 var1"
  end

  # somehow embed my_function() here without having to re-implement it
end

defmodule Main do
  def print_data do
    M1.my_function()
    M2.my_function()
  end
end

===>

"***my name: M1. My current value: M1 var1"
"***my name: M2. My current value: M2 var1"

我知道行为和协议。然而,我如何才能 嵌入 my_function 在其他模块中,并使其以所需的方式工作?

elixir
1个回答
1
投票

回答标题中的问题。

动态调度 可与 Kernel.apply/3.


0
投票

小心。 我强烈不鼓励你这样做 除非你完全明白它是如何工作的。

要获得访问 __MODULE__ 变量的方式,你需要注入AST,而不是调用函数。也就是说,你需要的是一个宏,而不是一个常规函数。

defmodule Injected do
  defmacro yo do
    caller = __CALLER__.module
    quote do
      IO.puts("***my name: #{unquote(caller)}. My current value: #{unquote(caller).var}")
    end
  end
end

而且,在目标模块中。

defmodule M do
  def var do
    "M1 var1"
  end

  import Injected

  def test, do: yo()
end

这使得它可以 召唤 你在一个模块内部的功能,但不是从外部,因为函数和宏都会被导入为 私人.


为了达到需要的目的,我们可以使用 Kernel.use/2.

defmodule Used do
  defmacro __using__(_) do
    caller = __CALLER__.module

    quote do
      def yo do
        IO.puts("***my name: #{unquote(caller)}. My current value: #{unquote(caller).var}")
      end
    end
  end
end

defmodule M do
  use Used

  def var do
    "M1 var1"
  end
end

M.yo()
#⇒ ***my name: Elixir.M. My current value: M1 var1
© www.soinside.com 2019 - 2024. All rights reserved.