唔,據說過這四個牛逼渣渣的behaviour:gen_server,gen_fsm,gen_event,supervisor。因此也就更加好奇behaviour的實現。函數
在解釋它是怎麼工做的以前,咱們能夠先看一個具體的實現。這可能會幫助咱們理解。atom
咱們先定義一個behaviour:spa
-module(my_behaviour). -export([behaviour_info/1]). -export([start/1, stop/0]). behaviour_info(callbacks) -> [ {init, 1}, {handle, 2}]; behaviour_info(_Other) -> undefined. start(Mod) -> State = Mod:init(0), {ok, State2} = Mod:handle(add, State), io:format("state : ~p~n", [State2]). stop() -> stop.
而後,咱們給他的callback給出具體的定義:code
-module(use_my_behaviour). -behaviour(my_behaviour). -export([init/1, handle/2]). init(State) -> io:format("init ~p~n", [State]), State. handle(Request, State) -> io:format("handle request:~p state:~p~n", [Request, State]), State2 = State + 1, {ok, State2}.
ok,而後是具體的執行:orm
$ erlc my_behaviour.erl $ erlc use_my_behaviour.erl use_my_behaviour.erl:2: Warning: behaviour my_behaviour undefined $ erl 1> my_behaviour:start(use_my_behaviour). init 0 handle request:add state:0 state : 1 ok 2> my_behaviour:module_info(). [{exports,[{behaviour_info,1}, {start,1}, {stop,0}, {module_info,0}, {module_info,1}]}, {imports,[]}, {attributes,[{vsn,[81274671739413406355698544269213408364]}]}, {compile,[{options,[{outdir,"/Users/luozhenxing/work/erlang/behaviour"}]}, {version,"4.9.4"}, {time,{2014,7,2,14,56,19}}, {source,"/Users/luozhenxing/work/erlang/behaviour/my_behaviour.erl"}]}] 3> my_behaviour:behaviour_info(callbacks). [{init,1},{handle,2}]
咱們來看看咱們作了什麼,先看behaviour的定義:server
1. 須要一個叫behaviour_info的函數,它的參數只有一個,是一個atom,叫作callbacks。blog
2. 而後,它的返回是a list of tuples,這些tuple定義了具體的callback的名字,以及他們的參數個數。接口
3. behaviour具體的執行代碼,雖然咱們已經給出了callback的接口,可是總要作點什麼的,要否則就不叫behaviour了。如上面的start(Mod),咱們在這裏使用了Mod中具體的init和handle方法。it
接着看behaviour使用的時候,事實上,也只是具體定義了behaviour須要的每一個callbacks。io
因此咱們能夠得出結論:
1. hehaviour的定義其實仍是使用的module的模板,因此,能夠說它是一種特殊的module。
2. 咱們能夠在定義一個module的時候,只寫一些共性的行爲,同時爲一些特殊的方法留下callback接口,這一module就是the behaviour module;而後,在具體使用的時候,實現不一樣的callbacks便可,這一module就是the callback module。這一機制就是behviour機制了。
3. 顯然,一個behaviour module,咱們是能夠寫不少個callback module配套使用的。
另外,R15B以後,提供了另一種新的定義behaviour的方法(看起來是否是和spec很像?):
-module(some_behaviour). -callback init( number() ) -> number(). -callback handle( Event :: atom(), ARG::number() ) -> number().
這樣作,和「先定義behaviour_info(callback),而後再將其export出去」效果是同樣的;不一樣的是,這樣定義以後,Dialyzer能夠方便的知道是否是出了什麼問題。