2015-09-01 17 views
6

Beim Versuch, ein benutzerdefiniertes Verhalten in Erlang zu definieren, kann ich keine Möglichkeit finden, die Callback-Funktion innerhalb des Verhaltensdefinitionsmoduls anzuwenden. Der Compiler behauptet, die Callback-Funktion ist nicht definiert.Wie erstelle ich ein benutzerdefiniertes Erlang-Verhalten?

Ich erwartete, dass eine Callback-Funktion in einem Verhalten wie eine abstrakte Methode in einer OO-Sprache funktioniert, in der die Methode ohne Angabe der Implementierung verwendet werden kann.

Das folgende Beispiel definiert eine Callback-Funktion fn. Dann wird diese Funktion in add_one verwendet. Was fn tatsächlich tut, wird durch das Erlang-Modul gesteuert, das dieses Verhalten implementiert.

-module(mybeh). 

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

-export([add_one/1]). 

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

Aber wenn ich versuche, die Datei mybeh.erl zu kompilieren, erhalte ich die folgende Fehlermeldung:

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

Codebeispiele I auf erlangcentral.org gefunden, learnyousomeerlang.com oder metajack.im waren zu einfach um diesen Fall zu decken. Ich hatte auch kein Glück damit, mich durch bekannte Erlang-Projekte auf Github zu schleichen (hätte mir aber mehr Mühe geben können).

Antwort

8

Sie sind sehr nah dran. Es ist tatsächlich einfacher als das, was Sie versucht haben:

Der Compiler kann das vollständig verstehen, so wie es ist.

So einfach, seine Art von Antiklimak.

EDIT

"Cool Geschichte, wie zu benutzen?"

Nichts spricht wie ein funktionierendes Beispiel:

Hier haben wir einen abstrakten Service. Es soll auf ein sehr enges Nachrichtenspektrum reagieren und alles andere lächerlich machen. Sein spezielles Element ist jedoch, dass es als Start-Argument den Namen eines Moduls akzeptiert, das einen bestimmten Aspekt von sein Verhalten definiert - und dies ist das Callback-Modul.

-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. 

hier So definieren wir einen wirklich einfachen Callback-Modul, in Übereinstimmung mit dem Verhalten wie 'my_behavior' oben definiert:

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

fn(A) -> A + 1. 

Hier ist es in Aktion!

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 

Also was ist die Verhaltensdefinition gut? Es tat nicht wirklich tun alles! Nun, was nützen all diese Dialyzer-Typ-Hierarchiedeklarationen? Sie tun auch nichts.Aber sie helfen Ihnen, Ihre Arbeit automatisch zu überprüfen, um sicherzustellen, dass Sie keinen aufregenden Runtime-Fehler erleben - aber weder Dialyzer noch Verhaltensdefinitionen zwingen Sie zu etwas: Sie warnen uns lediglich vor unserem (wahrscheinlich) bevorstehenden Untergang:

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

haha_wtf(A) -> A - 1. 

und wenn wir das bauen wir erhalten:

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

Beachten Sie jedoch, dass dieses Modul war tatsächlich kompiliert und ist nach wie vor unabhängig nutzbar (aber nicht von unserem abstrakten Service, der fn/1 zu finden erwartet definiert in irgendetwas genannt my_behavior):

11> my_other_callbacks:haha_wtf(5). 
4 

Hoffentlich wirft diese kleine Walktour etwas Licht auf den Pfad.

+0

Eigentlich muss ich die Funktion apply_fn (jetzt add_one) zu arbeiten. Ich habe das Beispiel angepasst, um es klarer zu machen. –

+0

@ JörgenBrandt OK, ein bisschen Bearbeitung dort ... Das ist nicht schwer zu verstehen, aber um wirklich grok zu werden, benötigt man ein komplettes Beispiel, wenn man es zum ersten Mal sieht. – zxq9

+0

Danke für die bisherige Mühe. Sollte es nicht -module (my_behaviour) sein. in der ersten Zeile des ersten Snippets? Oder fehlt mir etwas? –

Verwandte Themen