在Elixir中打开模块?

时间:2015-02-03 05:18:31

标签: elixir

Ruby有开放的类,非常方便(虽然受到一些人的谴责),Elixir大量借用Ruby,所以我希望Elixir允许我重新打开一个模块并在关闭后添加宏,但这样做了不按我试用的方式工作。有办法做到这一点吗?这个功能在Elixir中是否可用?

为了具体化,让我们以Chris McCord的Metaprogramming Elixir为例:

defmodule Math do
  defmacro say({:+, _, [lhs, rhs]}) do 
    quote do
      lhs = unquote(lhs)
      rhs = unquote(rhs)
      result = lhs + rhs
      IO.puts "#{lhs} plus #{rhs} is #{result}"
      result
    end
  end

  defmacro say({:*, _, [lhs, rhs]}) do 
    quote do
      lhs = unquote(lhs)
      rhs = unquote(rhs)
      result = lhs * rhs
      IO.puts "#{lhs} times #{rhs} is #{result}" 
      result
    end 
  end
end

如果我然后为减法添加一个宏

defmodule Math do
  defmacro say({:-, _, [lhs, rhs]}) do
    quote do
      lhs    = unquote(lhs)
      rhs    = unquote(rhs)
      result = lhs - rhs
      IO.puts "#{lhs} minus #{rhs} is #{result}"
      result
    end
  end
end

我收到警告,我正在重新定义模块Math,并且最初定义的宏会失败。显然我的方法不是正确的方法,但有另一种方法可以实现同样的目标吗?

1 个答案:

答案 0 :(得分:17)

您无法重新打开模块。由于Elixir是一种编译语言,从源代码到可执行表示的方式是单向的。在编译期间会评估更改代码的机制,例如宏。但是,Elixir允许你进行热代码交换,i。即您可以在运行时替换已编译的模块。

我认为这有一些有趣的含义。您可以在运行时更改程序 - 实际上,您可以控制源代码,这样您就可以更换模块的各个部分而无需更改其他部分。不过,我喜欢把所有东西放在一个地方的想法。在Elixir中,当你看一个模块时,你确切知道你有什么*。

因此,如果这个问题只是一个方便的开发工作流程 - 最接近Ruby的方法是将类的方法保存到文件中并从iex重新编译它去。


*严格来说,只要查看模块,您就可以确切知道正在运行的代码。当您使用协议时,您还需要查看所有协议实现,这些实现可能分散在整个代码库中,或者更糟糕的是,它们可能分布在多个应用程序中。