Несоответствие шаблону в Erlang

Я делаю этот звонок:

add(Login, Pass, Role) ->
  gen_server:call(?SERVER, {add, Login, Pass, Role}).

и я ожидаю, что это будет соответствовать:

handle_call(State, {add, Login, Pass, Role}) ->
  io:format("add ~n"),
  Db = State#state.db,
  case lists:keyfind(Login, 1, Db) of
    false->
      io:format("add - reg new ~n"),
      {reply, registered, State#state{db=[{Login, erlang:md5(Pass), Role, ""}|Db]}};
     {Key, Result}-> 
      {reply, invalid_params, Db}  
  end.

но он всегда идет к:

handle_call(_Request, _From, State) ->
  io:format("undef ~n"),
  Reply = ok,
  {reply, Reply, State}.

Что случилось?


person Alexander Shavelev    schedule 20.01.2015    source источник


Ответы (2)


Поведение кажется действительным,

handle_call имеет такую ​​спецификацию:

-spec(handle_call(Request :: term(), From :: {pid(), Tag :: term()},
    State :: #state{}) ->
  {reply, Reply :: term(), NewState :: #state{}} |
  {reply, Reply :: term(), NewState :: #state{}, timeout() | hibernate} |
  {noreply, NewState :: #state{}} |
  {noreply, NewState :: #state{}, timeout() | hibernate} |
  {stop, Reason :: term(), Reply :: term(), NewState :: #state{}} |
  {stop, Reason :: term(), NewState :: #state{}}).

Если вы можете посмотреть здесь http://erlang.org/doc/man/gen_server.html#Module:handle_call-3

Кроме того, для поведения otp по умолчанию было бы лучше для начала использовать шаблоны. Например, для gen_server https://gist.github.com/kevsmith/1211350

Ваше здоровье!

person Evan P    schedule 20.01.2015

В модуле, использующем поведение gen_server, функция обратного вызова handle_call должна принимать три аргумента. Однако вы определили две разные функции, handle_call/2 и handle_call/3. (В Erlang функции с одинаковыми именами, но с разным количеством аргументов, считаются разными функциями.)

Поскольку модуль gen_server ищет только handle_call/3 и игнорирует handle_call/2, всегда вызывается ваша функция "undef".

Чтобы исправить это, измените функцию так, чтобы она принимала (игнорируемый) второй аргумент, и поместите запрос первым, а состояние последним:

handle_call({add, Login, Pass, Role}, _From, State) ->

и измените end. на end;. разделяет разные функции, а ; разделяет разные предложения одной и той же функции.

person legoscia    schedule 20.01.2015
comment
State — последний параметр: это handle_call(Req, _From, State). - person Roger Lipscombe; 20.01.2015
comment
Спасибо! Не заметил... Сейчас исправлено. - person legoscia; 20.01.2015
comment
handle_cast/2 принимает 2 аргумента, handle_call/3 всегда принимает 3, gen_event имеет handle_call/2 - person Evan P; 20.01.2015