5

我刚刚学习了如何在 Erlang 中升级模块,并且我知道只有使用完全限定名称(例如module:function())的函数调用才会“重新链接”到加载到 VM 中的当前版本,但没有指定的函数调用模块的名称不会“重新链接”到当前版本,而是继续使用旧版本。

关于何时使用完全限定的函数调用以及何时可以仅通过函数名称调用函数,是否有经验法则?使用全名(如 )调用所有函数是不是一个坏主意module:function()

4

1 回答 1

9

Erlang 应用程序通常使用像gen_serverand这样的标准行为gen_fsm,它们已经在其内部循环中包含完全限定的函数调用,因此会处理这个问题。

但是,如果由于某种原因,您不得不编写带有自己的递归消息处理循环的模块,并且希望该模块在运行时可升级,则该循环需要包含一个完全限定的递归调用,通常您会放置这个在处理特定升级消息的代码部分中,类似于与标准行为一起使用的回调模块中预期的code_change/3函数。

例如,考虑下面的循环,它类似于标准行为,但大大简化:

loop(Callbacks, State) ->
    {{Next, NState},DoChange} =
        receive
            {code_change, ChangeData} ->
                {Callbacks:handle_code_change(ChangeData, State), true};
            {cast,Data} ->
                {Callbacks:handle_cast(Data,State), false};
            {call,From,Data} ->
                Result = Callbacks:handle_call(Data,State),
                case Result of
                    {reply, Reply} ->
                        From ! Reply;
                    _ ->
                        ok
                end,
                {Reply, false};
            Message ->
                {Callbacks:handle_info(Message,State), false}
        end,
    case Next of
        stop -> ok;
        _ ->
            case DoChange of
                true -> ?MODULE:loop(Callbacks, NState);
                false -> loop(Callbacks, NState)
            end
    end.

loop/2函数有两个参数:Callbacks,一个回调模块的名称,期望导出为特定消息调用的特定函数,以及State,它对循环不透明,但可能对回调模块有意义。循环是尾递归的,它通过调用特定的回调函数来处理几个特定的​​消息,然后通过调用handle_info/2回调模块来处理任何其他消息。(如果您使用过标准行为,您会发现这种方法很熟悉。)回调函数返回一个Next值,以及一个要传递给下一个循环的新状态。如果Nextstop,我们退出循环,否则我们检查 的值DoChange,它被设置为true仅用于代码更改消息,如果为真,则循环使用完全限定的调用调用自身,否则它仅使用常规调用。

如前所述,这一切都大大简化了。您需要编写自己的循环非常罕见,如果您这样做,还有其他重要的事情没有在这里显示,例如您需要处理的系统消息。你最好使用标准行为。

于 2015-10-03T14:38:31.007 回答