首页 > 代码库 > [Erl_Question16]为什么要用MFA代替fun()–>end?

[Erl_Question16]为什么要用MFA代替fun()–>end?

MFA:Module Function Arguments.

首先你要知道Module:Func(Args)和Func(Args)的区别在哪里?

如果对细节感兴趣,可以通过这里了解:http://www.cnblogs.com/zhongwencool/p/erlang_hot_code.html

总之:Erlang函数有local call和external call的区别,Local call 就是在函数在被定义的模块里面被调用,可以直接被调用: Func(Args); External call 就是显式的使用Module:Func(Args)来调用或import别的模块进来的调用.

当同一个模块有2个版本被加载里,所有的local call都可以工作在当前版本状态,但是:external call只能调用到最新的版本!

1.使用Fun的情景:

       1.1 先启动1个shell终端,分别名为test1:

erl -name test1

       1.2 test1加载模块mfa_test.erl

-module(mfa_fun).-export([cal/2,func/0]).cal(X,Y) ->     X+Y.func() ->       fun(X,Y) -> cal(X,Y) end.

1.3在shell中输入:

>Func = mfa_fun:func().#Fun<mfa_fun.1.52492151>>Func(1,2).3

2.使用MFA的场景:

改变mfa_test.erl中cal函数并重新加载这个模块:

cal(X,Y) -> X*Y .

1.5 再运行:

>Func(1,2).3

可以看到这个Func运行的local版本,如果把func改为以下版本:

func() ->       fun(X,Y) -> ?MODULE:cal(X,Y) end.

那么结果是永远调用的最新版本代码,有兴趣可以自己验证下,你会感到好神奇,为什么Func变量是没有变化,但得到的结果却发生了变化。。。


那么我们可以再进一步想一下:

我们经常使用spawn(Func)来创建一个新的进程,如果我们永远不升级还好,如果热升级,会发生什么情况?

这个local call的func,你怎么也改不了它,所以正常情况下最好使用:

spawn(Mod,FuncName,Args)来创建进程,这样不会影响升级。

再进一步,就是进程里面所有存local call都是无法被升级的,最佳实践就是一直用MFA就好!


answer

 

     选择比努力重要,及时感恩,珍惜生活