如何创建和使用自定义Erlang行为? [英] How to create and use a custom Erlang behavior?

查看:104
本文介绍了如何创建和使用自定义Erlang行为?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

尝试在Erlang中定义自定义行为,我无法找出一种在行为定义模块中应用回调函数的方法。编译器声称,回调函数是未定义的。

Trying to define a custom behaviour in Erlang, I cannot figure out a way to apply the callback function inside the behaviour definition module. The compiler claims, the callback function is undefined.

我期望一个行为中的回调函数就像一个OO语言中的抽象方法一样工作,使用该方法而不指定实现。

I was expecting a callback function in a behaviour to work just like an abstract method in an OO language where it is possible to use the method without specifying the implementation.

下面的示例定义了一个回调函数fn。然后,该函数在add_one中使用。实际执行的是什么是由执行此行为的Erlang模块控制的。

The below example defines a callback function fn. Then, that function is used in add_one. What fn actually does is controlled by the Erlang module implementing this behaviour.

-module( mybeh ).

-callback fn( A::number() ) -> B::number().

-export( [add_one/1] ).

add_one( A ) ->
  1+fn( A ).

但是当我尝试编译文件mybeh.erl时,会收到以下错误消息: p>

But when I try to compile the file mybeh.erl, I get the following error message:

$ erlc mybeh.erl
mybeh.erl:8: function fn/1 undefined

我在 erlangcentral.org ,learnyousomeerlang.com或metajack.im太简单,无法涵盖这种情况。我也没有任何运气,通过Github上的知名Erlang项目(可能会尝试更难)。/ b>

Code examples I found on erlangcentral.org, learnyousomeerlang.com or metajack.im were too simplistic to cover this case. Neither did I have any luck with grepping my way through well known Erlang projects on Github (could have tried harder though).

推荐答案

你很近它实际上比你尝试的更容易:

You are very close. It is actually easier than what you tried:

-module(my_behavior).

-callback fn(A :: term()) -> B :: term().

编译器可以完全理解这一点,就像这样。

The compiler can understand this fully, just as it is.

很简单,它的反意思。

编辑

酷的故事,如何使用

没有什么可以说是一个工作的例子:

Nothing speaks like a working example:

这里我们有抽象的服务。它应该是响应一个非常狭窄的消息,并嘲笑任何其他。它的特殊元素是,它接受作为其启动参数的模块的名称,该模块定义了其行为的某些特殊方面 - 这是回调模块。

Here we have an abstract service. It is supposed to respond to a very narrow spectrum of messages, and ridicule anything else. Its special element, though, is that it accepts as its startup argument the name of a module which defines some special aspect of its behavior -- and this is the callback module.

-module(my_abstract).
-export([start/1]).

start(CallbackMod)->                
    spawn(fun() -> loop(CallbackMod) end).

loop(CBM) ->
    receive
        {Sender, {do_it, A}} ->
            Sender ! CBM:fn(A),
            loop(CBM);
        stop ->
            io:format("~p (~p): Farewell!~n",
                      [self(), ?MODULE]);
        Message ->
            io:format("~p (~p): Received silliness: ~tp~n",
                      [self(), ?MODULE, Message]),
            loop(CBM)
    end.

所以这里我们定义一个非常简单的回调模块,根据定义为'my_behavior'以上:

So here we define a really simple callback module, in accordance with the behavior defined as 'my_behavior' above:

-module(my_callbacks).
-behavior(my_behavior).
-export([fn/1]).

fn(A) -> A + 1.

这是在行动!

1> c(my_behavior).
{ok,my_behavior}
2> c(my_abstract).
{ok,my_abstract}
3> c(my_callbacks).
{ok,my_callbacks}
4> Service = my_abstract:start(my_callbacks).
<0.50.0>
5> Service ! {self(), {do_it, 5}}.
{<0.33.0>,{do_it,5}}
6> flush().
Shell got 6
ok
7> Service ! {self(), {do_it, 41}}.
{<0.33.0>,{do_it,41}}
8> flush().                        
Shell got 42
ok
9> Service ! stop.
<0.50.0> (my_abstract): Farewell!
stop

那么行为定义有什么好处?它没有实际上任何东西!那么所有这些Dialyzer类型的层次结构声明是什么?他们也不做任何事情。但是,它们可帮助您自动检查您的工作,以确保您不会遇到一些令人兴奋的运行失败 - 但是透析员和行为定义都不会强制您做任何事情:他们只是警告我们(可能)即将到来的厄运:

So what good is the behavior definition? It didn't actually do anything! Well, what good are all those Dialyzer type hierarchy declarations? They don't do anything either. But they help you automatically check your work to make sure you won't experience some exciting runtime fail -- but neither Dialyzer nor behavior definitions force you to do anything: they merely warn us of our (likely) impending doom:

-module(my_other_callbacks).
-behavior(my_behavior).
-export([haha_wtf/1]).

haha_wtf(A) -> A - 1.

当我们构建它时,我们得到:

And when we build this we get:

10> c(my_other_callbacks).
my_other_callbacks.erl:2: Warning: undefined callback function fn/1 (behaviour 'my_behavior')
{ok,my_other_callbacks}

但是,请注意,这个模块实际上已被编译,并且仍然可以独立使用(但不是由我们的抽象服务,这是期望找到 fn / 1 定义在任何所谓的 my_behavior ):

Note, though, that this module was actually compiled and is still independently useable (but not by our abstract service, which is expecting to find fn/1 defined in anything called a my_behavior):

11> my_other_callbacks:haha_wtf(5).
4

希望这个小小的演练在路上散发了一些光。

Hopefully this little walkthrough sheds some light on the path.

这篇关于如何创建和使用自定义Erlang行为?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆