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