Erlang关键字之behaviour

使用 Erlang 编程的人都知道 OTP,而基于OTP 框架创建进程的时候,常用的有四大 behaviour: 

  • supervisor
  • gen_server
  • gen_fsm
  • gen_event

1.behaviour的定义以及用途?

定义:在 erlang 的编译器中,behaviour 的作用是用来定义一个规约。定义好这个规约之后,任何遵守这个规约的模块,必须按照规约中的要求,使用 -export([]). 导出对应的函数,导出完这些函数后,这些导出函数的调用将由 behaviour 统一支配。behaviour 只不过是实现代码组织的一种手段而已,behaviour 就是把代码分成 通用部分 ,以及每一个回调模块需要去做的 特殊部分 。这样就好理解了,于是 使用 -behaviour() 定义的模块都是这个 behaviour 所要求实现的回调模块 。 

2.是否能自定义behaviour?

这是可以的,如果大家代码读得多了,就应该发现,很多优秀的开源项目中就自定义了 behaviour。例如经典的 rabbitmq 中,就将 erlang 自带的 gen_server 进行了改进,写了一个 gen_server2 的 behaviour,因为 gen_server 中的消息队列是一个普通消息队列不能满足需要,改进后的 gen_server2 使用了带优先级的消息队列。当然了,在 erlang 本身的底层代码里面,也有写过很多 behaviour,不细说了,总之 erlang 可以自定义 behaviour 。 

3.如何定义一个behaviour?

要定义一个 behaviour,首先你要创建一个模块,它必须导出 behaviour_info/1 这个函数(注意 behaviour 是 带 u 的),函数定义如下:

behaviour_info(callbacks) ->
    [{foo, 0}, {bar, 1}, {baz, 2}];

behavior_info(_) ->
    undefined.

传入 callbacks 参数,必须返回一个包含导出函数和参数个数的列表。 

这些导出函数,就是这些回调模块所特有的部分,而通用部分,则写在 behaviour 中。比如在 gen_server 中,当一个进程收到一个消息,在 behaviour 行为模型中,它会处理大部分通用的逻辑,例如,如果是 call 消息,它会根据 handle_call 函数的返回值对 From 进程发送返回消息,同时,处理完消息后,它会继续循环进行消息处理,不多说,亮代码: 

handle_msg({'$gen_call', From, Msg}, GS2State = #gs2_state { mod = Mod,  
                                                             state = State,  
                                                             name = Name,  
                                                             debug = Debug }) ->  
    case catch Mod:handle_call(Msg, From, State) of %%大家注意了,这里就是调用了模块中的handle_call()函数,并且获取它的返回值  
        {reply, Reply, NState} ->  
            Debug1 = common_reply(Name, From, Reply, NState, Debug),  
            loop(GS2State #gs2_state { state = NState,%%在这里,处理完一条消息之后,继续转入到循环中去  
                                       time  = infinity,  
                                       debug = Debug1 });  

        {reply, Reply, NState, Time1} ->  
            Debug1 = common_reply(Name, From, Reply, NState, Debug),  
            loop(GS2State #gs2_state { state = NState,  
                                       time  = Time1,  
                                       debug = Debug1});  
        {noreply, NState} ->  
            Debug1 = common_debug(Debug, fun print_event/3, Name,  
                                  {noreply, NState}),  
            loop(GS2State #gs2_state {state = NState,  
                                      time  = infinity,  
                                      debug = Debug1});  
        {noreply, NState, Time1} ->  
            Debug1 = common_debug(Debug, fun print_event/3, Name,  
                                  {noreply, NState}),  
            loop(GS2State #gs2_state {state = NState,  
                                      time  = Time1,  
                                      debug = Debug1});  
        {stop, Reason, Reply, NState} ->  
            {'EXIT', R} =  
                (catch terminate(Reason, Msg,  
                                 GS2State #gs2_state { state = NState })),  
            reply(Name, From, Reply, NState, Debug),  
            exit(R);  
        Other ->  
            handle_common_reply(Other, Msg, GS2State)  

    end;

4.怎么使用behaviour?

使用的时候,需要在模块开头 使用: 

-behaviour(behaviour_name).

同时需要定义并且使用 -export([]) 导出这个 behaviour 所要求的导出函数。 
注意了, 一个模块是可以有多个 -behaviour(behaviour_name). 的 ,也就是说,这个模块的一部分函数可以既是 A behaviour 的回调模块,又是 B behaviour 的回调模块。 

5.何时使用behaviour?

  最后这个话题就比较广了,这是一个没有绝对意义正确的问题,在 erlang OTP 中,那几个主要进程的实现都是使用 behaviour 封装了基本的操作。 

      对于 behaviour 和进程的关系,我曾经有过这样的疑惑,只有在创建进程的时候才能用 behaviour 吗?最后得到的结论是:没有关系! 因为在 erlang 的设计理念当中,模块与进程,这是两个概念,而 behaviour 与模块的组织相关,因此它与进程没有必然联系。 

 

原文地址:https://blog.csdn.net/zhangzhizhen1988/article/details/8499871?spm=a2c6h.12873639.0.0.6fc23877YVhE8t

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值