我来自 Java 和 Ruby 背景,我想知道 Erlang 中是否有任何等效的“method_missing”。我查看了文档,我能看到的最接近的是 erl_eval 和 erl_parse 的使用,但我想知道是否还有其他方法?
5 回答
当您尝试调用未定义的函数时,会调用“error_handler”模块。
process_flag(error_handler, Module).
该模块需要导出undefined_function/3
和undefined_lambda/3
. 您可以看到这应该如何在标准处理程序模块中实现,error_handler
.
你需要自己小心error_handler
不要破坏标准的代码加载系统。Erlang 通常会尝试从未定义的函数错误中加载模块并在放弃并发出错误信号之前重新运行该函数。您通常想先尝试标准的 error_handler,如果失败,则回退到您的新行为。
archaelus 指出了一个好的方向,但是如果你不想干预error_handler
,它确实支持一个很好的回调例程,通知被调用的模块有一个调用未定义函数的尝试,这看起来很方便。
https://github.com/erlang/otp/blob/maint/lib/kernel/src/error_handler.erl#L139
因此,如果您将其添加到模块中:
'$handle_undefined_function'(Func, Args) ->
io:format("Called undefined function '~p' with args ~p.~n", [Func, Args]).
每当调用该模块中的未定义函数时,它都会打印出一条消息。
如果你喜欢“防御性编码”,你可以调用Module:module_info(exports)
看看你要调用的函数是否被导出。
Erlang 有函数而不是方法,通常试图调用未定义的函数被认为是错误的。
如果您尝试在同一模块中调用不存在的函数,编译器会生成错误。尝试调用另一个模块中的函数会在运行时产生错误,undef
error. 您希望如何处理此类错误取决于您的应用程序。
我在调用端使用了类似的模式,其中模块可能提供日志级别分类功能(可能返回无效结果)。我这样做:
-spec categorize(atom(), integer()) -> log_classification().
categorize(Module, Code) ->
case catch(Module:ns_log_cat(Code)) of
info -> info;
warn -> warn;
crit -> crit;
_ -> info % Anything unknown is info (this includes {'EXIT', Reason})
end.
由于没有方法(通常,您当然可以创建一个 OO 行为并使用消息实现它,然后 have method_missing
,被调用者不知道我尝试了任何东西,因此它无法解释它。