2015-01-13 2 views
2

Я пытаюсь сделать написать и скомпилировать пользовательское поведение в Erlang.Написание и компиляция пользовательских поведений в Erlang

Я не могу найти четкой документации о том, как скомпилировать это поведение.

-module(bla). 

-export([start_link/0,behaviour_info/1]). 

behaviour_info(callbacks)-> 
    [{init,1}]; 
behaviour_info(_Other)-> 
    undefined. 

%% -callback init(Args :: term()) -> 
%%  {ok, State :: term()} | {ok, State :: term(), timeout()} | 
%%  {stop, Reason :: term()} | ignore. 

start_link()-> 
    init([]). 

моя команда для comiling является:

erlc.exe .\src\bla.erl 

В РЕЗУЛЬТАТЕ:

bla.erl:24: function init/1 undefined 

Любой мысль о написании и составлении поведения в Эрл, пожалуйста? любые ссылки?

ответ

2

Определение обратных вызовов поведения приводит к обязательству по выполнению модуля обратного вызова. В erlang модули - это просто контейнеры функций, а не классы и интерфейсы. Поведение основано на разрешении имени модуля времени исполнения Mod:fun(). OTP gen_server (проверьте) сохраняет обратный вызов имя модуля после передать его в: gen_server:start_link(CallbackModuleName, Args, Opts), и вот код applying callbackinit/1:

init_it(Starter, Parent, Name0, Mod, Args, Options) -> 
    Name = name(Name0), 
    Debug = debug_options(Name, Options), 
    case catch Mod:init(Args) of 
     {ok, State} -> 
      proc_lib:init_ack(Starter, {ok, self()}), 
      loop(Parent, Name, State, Mod, infinity, Debug); 
     {ok, State, Timeout} -> 
      proc_lib:init_ack(Starter, {ok, self()}), 
      loop(Parent, Name, State, Mod, Timeout, Debug); 
     ... 

Это применение init/1 пройденного модуль обратного вызова хранится в Mod параметре, получает последнее значение, делать то, что вы хотите, и продолжать идти (или нет, зависит от последнего значения).

Предположим, что мы имеем модуль bla_impl который выглядит следующим образом:

-module(bla_impl). 
-behaviour(bla). 
-export([init/1, start_link/0]). 

start_link() -> bla:start_link(?MODULE). %% macro ?MODULE is resolved to bla_impl 
init(Args) -> ... . 

И теперь вы должны сказать в бла, какой модуль используется по:

-module(bla). 
-export([start_link/1]). 

start_link(Mod) -> Mod:init([]). 

или, может быть, лучшим решением будет читать от конфигурации:

-module(bla). 
-export([start_link/0]). 

start_link() -> 
    Mod = application:get_env(bla_app, callback_module), 
    Mod:init([]), 
    ... 

Существует много способов сделать это.

Как вы видите, здесь нет магии. Это могло бы работать даже без -behaviour(bla), а не с обратным вызовом с -callback. Это всего лишь информация для компилятора, инструментов и документации.

Из Erlang документации: Behaviours

И кстати. start_link Функция должна порождать другой процесс и ссылаться на него.

start_link(Mod) -> 
    spawn_link(Mod, init, [[]]). 
+0

Получил это! На самом деле не волшебство! Спасибо Лукасу за этот быстрый и ясный ответ. – Cavet