3

モジュール内のローカル関数を呼び出して、コードの変更後に最新バージョンのコードが使用されるようにする方法がわかりません。次の例を参照してください。

1  -module(test).
2
3  -export([start/0, call/1]).
4  -export([loop/0, add/1]).
5
6  start() ->
7      register(foo, spawn(test, loop, [])).
8
9  call(X) ->
10     foo ! {self(), X},
11     receive
12         Y -> Y
13 end.
14
15 loop() ->
16     receive
17         {Pid, Z} -> Pid ! add(Z)
18     end,
19     loop().
20
21 add(N) ->
22     N + 1.

変更される機能はですadd/1。最新バージョンの関数を使用するには、add/1(17行目)の呼び出しが完全修飾関数呼び出し {Pid, Z} -> Pid ! ?MODULE:add(Z)である必要があります。私がそれを試してみると、私はこれを手に入れます:

1> c(test). 
{ok,test}
2> test:start(). 
true
3> test:call(1).
2

22行目はに変更されましたN + 2

4> c(test).     
{ok,test}
5> test:call(1).
3

22行目が再びに変更されましたN + 3

6> c(test).     
{ok,test}
7> test:call(1).
** exception error: bad argument
    in function  test:call/1 (test.erl, line 10)

なぜこのエラーが発生するのですか?

4

1 に答える 1

4

新しいモジュールをロードして使用するにloop/0は、関数ではなく、完全に修飾されたバージョンの関数を最終的に呼び出す必要があると思います。add/1コードロードメカニズムは、モジュールの2つの実行中のバージョンを同時に処理するように準備されており、の例N+3はモジュールの3番目のロードです。最初のバージョンは強制的に削除されます。

代わりに、このループを試してください。

15 loop() ->
16     receive
17         {Pid, Z} -> Pid ! add(Z)
18     end,
19     ?MODULE:loop().

の次回の実行時に最新バージョンをリロードするように変更しましたloop/0

より一般的なのはreload、メインループを明示的に直接呼び出すメッセージなどを使用して、要求ごとにモジュールを常にリロードするオーバーヘッドを回避することです。

于 2012-06-14T22:28:28.300 に答える