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,并且最初定义的宏会失败。显然我的方法不是正确的方法,但有另一种方法可以实现同样的目标吗?
答案 0 :(得分:17)
您无法重新打开模块。由于Elixir是一种编译语言,从源代码到可执行表示的方式是单向的。在编译期间会评估更改代码的机制,例如宏。但是,Elixir允许你进行热代码交换,i。即您可以在运行时替换已编译的模块。
我认为这有一些有趣的含义。您可以在运行时更改程序 - 实际上,您可以控制源代码,这样您就可以更换模块的各个部分而无需更改其他部分。不过,我喜欢把所有东西放在一个地方的想法。在Elixir中,当你看一个模块时,你确切知道你有什么*。
因此,如果这个问题只是一个方便的开发工作流程 - 最接近Ruby的方法是将类的方法保存到文件中并从iex重新编译它去。
*严格来说,只要查看模块,您就可以不确切知道正在运行的代码。当您使用协议时,您还需要查看所有协议实现,这些实现可能分散在整个代码库中,或者更糟糕的是,它们可能分布在多个应用程序中。