我的 gen_server 实施有什么问题?
What's wrong with my gen_server implementation?
根据 LYSE 书,我尝试用 gen_server 重新实现 kitty_server2。但出于某种原因,我收到此错误:
37> Cat1 = kitty_server3:order_cat(Pid, carl, brown, 2).
Ordeirng cat!** exception exit: {{function_clause,
[{gen,do_for_proc,
[{ok,<0.162.0>},#Fun<gen.0.132519590>],
[{file,"gen.erl"},{line,252}]},
{gen_server,call,2,[{file,"gen_server.erl"},{line,200}]},
{erl_eval,do_apply,6,[{file,"erl_eval.erl"},{line,673}]},
{erl_eval,expr,5,[{file,"erl_eval.erl"},{line,438}]},
{shell,exprs,7,[{file,"shell.erl"},{line,686}]},
{shell,eval_exprs,7,[{file,"shell.erl"},{line,641}]},
{shell,eval_loop,3,[{file,"shell.erl"},{line,626}]}]},
{gen_server,call,[{ok,<0.162.0>},{order,carl,brown,2}]}}
in function gen_server:call/2 (gen_server.erl, line 204)
我似乎已经实现了所有必需的回调,但我无法真正判断错误的含义。它是说我缺少回调吗?因为它似乎甚至没有调用相关的 handle_call
?
这是完整的服务器实现:
-module(kitty_server3).
-behaviour(gen_server).
-export([order_cat/4, return_cat/2, close_shop/1, sell_cat/3, start/0, start_link/0]).
-export([init/1, handle_call/3, handle_cast/2, code_change/3,
handle_info/2, terminate/2]).
-record(cat, {name, color=green, price}).
start() -> gen_server:start(?MODULE, {[], 0}, []).
start_link() -> gen_server:start_link(?MODULE, {[], 0}, []).
%%% Client api
%% Asynchronous
return_cat(Pid, Cat = #cat{}) -> gen_server:cast(Pid, {return, Cat}).
%% Synchronous call
order_cat(Pid, Name, Color, Price) ->
io:format("Ordeirng cat!"),
gen_server:call(Pid, {order, Name, Color, Price}).
sell_cat(Pid, Cat, Price) ->
gen_server:call(Pid, {sell, Cat, Price}).
close_shop(Pid) -> gen_server:stop(Pid).
%%% Callback functions
init(State) -> {ok, State}.
%%% Server functions
%% Synchronous callbacks
handle_call({order, Name, Color, Price}, _From, {Cats, Money}) ->
io:format("Handling cat order.."),
if Cats =:= [] ->
io:format("1.."),
{reply, make_cat(Name, Color, Price), {Cats, Money + Price}};
Cats =/= [] -> % empty the stock
io:format("2.."),
{reply, hd(Cats), {tl(Cats), Money + Price}}
end;
handle_call({sell, Cat, Price}, _From, {Cats, Money}) ->
if Money >= Price ->
{reply, Price, {[Cat|Cats], Money - Price}}; % pay the customer!
Money < Price ->
{reply, 0, {Cats, Money}} % pay nothing we are poor!
end.
%% Asynchronous callbacks
handle_cast({return, Cat = #cat{}}, {Cats, Money}) ->
{noreply, {[Cat|Cats], Money}}.
%% Terminate callback
terminate(_Reason, {Cats, Money}) ->
release_the_cats(Cats, Money).
%% Code change callback
code_change(_OldVsn, State, _Extra) ->
{ok, State}.
%% Handle unexpected messages callback
handle_info(Info, State) ->
io:format("Unexpected message: ~w", [Info]),
{noreply, State}.
%%% Private functions
make_cat(Name, Col, Price) ->
#cat{name=Name, color=Col, price=Price}.
release_the_cats(Cats, Money) ->
io:format("Made $~w~n", [Money]),
[io:format("~p was set free.~n",[C#cat.name]) || C <- Cats].
有什么建议吗?
这对我来说非常好:
Eshell V7.2.1 (abort with ^G)
1> l(kitty_server3).
{module,kitty_server3}
2> {ok, Pid} = kitty_server3:start().
{ok,<0.36.0>}
3> kitty_server3:order_cat(Pid, carl, brown, 2).
Ordeirng cat!Handling cat order..1..{cat,carl,brown,2}
4>
也许您做了一些更改但没有正确重新加载模块,或者您的 Erlang shell 有一些旧的变量绑定?
根据 LYSE 书,我尝试用 gen_server 重新实现 kitty_server2。但出于某种原因,我收到此错误:
37> Cat1 = kitty_server3:order_cat(Pid, carl, brown, 2).
Ordeirng cat!** exception exit: {{function_clause,
[{gen,do_for_proc,
[{ok,<0.162.0>},#Fun<gen.0.132519590>],
[{file,"gen.erl"},{line,252}]},
{gen_server,call,2,[{file,"gen_server.erl"},{line,200}]},
{erl_eval,do_apply,6,[{file,"erl_eval.erl"},{line,673}]},
{erl_eval,expr,5,[{file,"erl_eval.erl"},{line,438}]},
{shell,exprs,7,[{file,"shell.erl"},{line,686}]},
{shell,eval_exprs,7,[{file,"shell.erl"},{line,641}]},
{shell,eval_loop,3,[{file,"shell.erl"},{line,626}]}]},
{gen_server,call,[{ok,<0.162.0>},{order,carl,brown,2}]}}
in function gen_server:call/2 (gen_server.erl, line 204)
我似乎已经实现了所有必需的回调,但我无法真正判断错误的含义。它是说我缺少回调吗?因为它似乎甚至没有调用相关的 handle_call
?
这是完整的服务器实现:
-module(kitty_server3).
-behaviour(gen_server).
-export([order_cat/4, return_cat/2, close_shop/1, sell_cat/3, start/0, start_link/0]).
-export([init/1, handle_call/3, handle_cast/2, code_change/3,
handle_info/2, terminate/2]).
-record(cat, {name, color=green, price}).
start() -> gen_server:start(?MODULE, {[], 0}, []).
start_link() -> gen_server:start_link(?MODULE, {[], 0}, []).
%%% Client api
%% Asynchronous
return_cat(Pid, Cat = #cat{}) -> gen_server:cast(Pid, {return, Cat}).
%% Synchronous call
order_cat(Pid, Name, Color, Price) ->
io:format("Ordeirng cat!"),
gen_server:call(Pid, {order, Name, Color, Price}).
sell_cat(Pid, Cat, Price) ->
gen_server:call(Pid, {sell, Cat, Price}).
close_shop(Pid) -> gen_server:stop(Pid).
%%% Callback functions
init(State) -> {ok, State}.
%%% Server functions
%% Synchronous callbacks
handle_call({order, Name, Color, Price}, _From, {Cats, Money}) ->
io:format("Handling cat order.."),
if Cats =:= [] ->
io:format("1.."),
{reply, make_cat(Name, Color, Price), {Cats, Money + Price}};
Cats =/= [] -> % empty the stock
io:format("2.."),
{reply, hd(Cats), {tl(Cats), Money + Price}}
end;
handle_call({sell, Cat, Price}, _From, {Cats, Money}) ->
if Money >= Price ->
{reply, Price, {[Cat|Cats], Money - Price}}; % pay the customer!
Money < Price ->
{reply, 0, {Cats, Money}} % pay nothing we are poor!
end.
%% Asynchronous callbacks
handle_cast({return, Cat = #cat{}}, {Cats, Money}) ->
{noreply, {[Cat|Cats], Money}}.
%% Terminate callback
terminate(_Reason, {Cats, Money}) ->
release_the_cats(Cats, Money).
%% Code change callback
code_change(_OldVsn, State, _Extra) ->
{ok, State}.
%% Handle unexpected messages callback
handle_info(Info, State) ->
io:format("Unexpected message: ~w", [Info]),
{noreply, State}.
%%% Private functions
make_cat(Name, Col, Price) ->
#cat{name=Name, color=Col, price=Price}.
release_the_cats(Cats, Money) ->
io:format("Made $~w~n", [Money]),
[io:format("~p was set free.~n",[C#cat.name]) || C <- Cats].
有什么建议吗?
这对我来说非常好:
Eshell V7.2.1 (abort with ^G)
1> l(kitty_server3).
{module,kitty_server3}
2> {ok, Pid} = kitty_server3:start().
{ok,<0.36.0>}
3> kitty_server3:order_cat(Pid, carl, brown, 2).
Ordeirng cat!Handling cat order..1..{cat,carl,brown,2}
4>
也许您做了一些更改但没有正确重新加载模块,或者您的 Erlang shell 有一些旧的变量绑定?