Определение обратных вызовов поведения приводит к обязательству по выполнению модуля обратного вызова. В 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, [[]]).
Получил это! На самом деле не волшебство! Спасибо Лукасу за этот быстрый и ясный ответ. – Cavet