2012-06-14 48 views
2

我不确定如何调用模块中的本地函数,以便在代码更改后将使用最新版本的代码。Erlang代码更改和本地函数调用

实施例:

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) 

为什么会出现这个错误?

回答

3

我相信你需要最终调用loop/0函数的完全限定版本,而不是add/1函数来加载和使用新模块。代码加载机制准备一次处理模块的两个运行版本,您的示例N+3第三个模块的加载 - 第一个版本被强制删除。

尝试,而不是这个循环:

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

我已经改变了它重新加载在loop/0的下一次执行的最新版本。

我相信更常见的是使用reload消息或类似的,将明确直接调用主循环,以避免不断重新加载模块在每个请求上的开销。

+0

它的工作原理,谢谢!所以我猜''loop/1'没有改变,第三次改变后它被擦除了。但是我仍然不明白为什么''MODULE:loop()'导致加载一个新版本的'add/1',为什么''MODULE:add()'和'loop/1'不一样? 。 – juro

+0

我认为这个技巧是'?MODULE:add()'要执行完成,然后该模块会蒸发。不要忘记,你可能有成千上万的进程在这个模块中执行,你不希望从下面的代码中改变代码 - 只有那些想改变的代码。 – sarnold

+2

有关代码替换的文档是:Erlang - 编译和代码加载http://www.erlang.org/doc/reference_manual/code_loading.html#id83918 – shino