Elixir 包药模块
例如,如果您有一个模块Elixir 包药模块,elixir,Elixir,例如,如果您有一个模块 defmodule Foo do # lots of "unknown" functions end 如何为该Foo创建包装器模块,如: defmodule Bar do # wrap all functions in Foo end 但是在Bar中,我想公开Foo中的所有函数,但另外我想在每个函数中添加一些代码,特别是我想尝试/捕获一个可以在任何Foo.error异常中显示的特定错误。。。我不想为Foo中的每个函数添加一个函数,因为这样做会重复 我可
defmodule Foo do
# lots of "unknown" functions
end
如何为该Foo
创建包装器模块,如:
defmodule Bar do
# wrap all functions in Foo
end
但是在Bar
中,我想公开Foo
中的所有函数,但另外我想在每个函数中添加一些代码,特别是我想尝试/捕获一个可以在任何Foo.error
异常中显示的特定错误。。。我不想为Foo
中的每个函数添加一个函数,因为这样做会重复
我可以用宏来实现这一点吗?AFAIU您希望通过复制类之间的继承逻辑来执行某种面向对象的编程。但这并不是像您可能已经知道的Elixir这样的函数式编程语言的哲学
然而,如果这真的是您想要做的,我发现它使用元编程,目标是做一些类似于您正在寻找的东西。不过看起来很复杂
编辑:在我们进一步讨论之后,我更了解你的问题。如果您想定义函数而不需要太多重复,那么元编程就是一种选择!下面是一个简单的示例,介绍如何通过元编程在模块中定义多个函数:
defmodule MyModule do
Enum.each ~w(method1 method2), fn(method_name) ->
def unquote(:"#{method_name}")(), do: unquote(method_name)
end
end
我不想为Foo中的每个函数添加函数,因为这样做会重复
我想这就是我要做的,但你确定这会是重复的吗
此外,您还可以使用,这将帮助您编写更少的错误处理函数:)这是defmacro的一个很好的用法,但一定要研究defedelegate。它允许您向其他/外部模块中的函数添加(委托)命名引用。借助元编程的魔力,一切都是可能的(但这并不总是有意义的):
defmodulebar do
代码。确保已编译(Foo)
对于{func,arity}handle_error()
结束
结束
结束
但是,这对宏不起作用。我不是出于在Elixir中复制OOP的错误愿望,而是将OP的问题解释为更接近于想要在模块上映射高阶函数(将函数发送到具有更好错误处理能力的函数),这似乎是一件相当实用的事情。@johncolman我同意!也许尝试进行元编程来复制Phoenix的action_fallback()的行为会有所帮助,但对我来说这看起来非常复杂,而编写一些函数,在每个函数中使用管道操作符调用一行,听起来并不是那么重复。我知道其原理不是以那种方式使用try/catch,但我仍然希望捕获在我正在使用的第三方模块中的任何函数中出现的特定错误wrapping@UjCorb我解决它的方法非常重复,因为在模块Bar
中,我定义了Foo
中的每个函数,但是我想象有一种方法可以解决它,只使用一个函数+一些宏魔法:)好:)我添加了一个简单的元编程示例来定义循环中的函数。也许你可以从那里开始。希望有帮助!有几种方法可以做到这一点,并且都涉及宏。在Foo中使用
实现defmacro\uu,然后在Bar
中添加use Foo
,或者在Bar模块中创建内联代码,该模块应读取Foo.\uu信息(:函数)
并在Bar中“重定义”所有内容。问题是你真的需要这个吗?这听起来像是一个糟糕的决定,记录继承的函数可能是一个棘手的问题。另一方面,当开发人员有条件地说“继承”genserver时,有许多类似的例子。这是通过use
完成的,在编译时执行宏\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu(..)时,在某些情况下有@beforecompleho。
defmodule Bar do
Code.ensure_compiled(Foo)
for {func, arity} <- Foo.__info__(:functions) do
args = Macro.generate_arguments(arity, __MODULE__)
def unquote(func)(unquote_splicing(args)) do
Foo.unquote(func)(unquote_splicing(args))
rescue
Foo.Error -> handle_error()
end
end
end