二郎gen_statem:错误bad_return_from_state_function
erlang gen_statem: error bad_return_from_state_function
我遇到了一个奇怪的问题。我得到了这个FSM(代码的内容不是很无能,所以我把它去掉了,现在只能看结构了):
start_link() ->
gen_statem:start_link({local, ?MODULE}, ?MODULE, [], []).
init([]) ->
io:format ("init", []),
Data={1},
{ok, packetsDeliver, Data}.
callback_mode() ->
[state_functions, state_enter].
packetsDeliver(enter, _OldState, Data) ->
io:format ("Key1", []),
{keep_state, Data};
packetsDeliver(info, _OldState, Data) ->
io:format ("Key2", []),
{keep_state, Data};
packetsDeliver(cast, _PacketData, Data) ->
io:format ("Key3", []),
{next_state, allPacketsDelivered, Data}.
allPacketsDelivered(enter, _OldState, Data) ->
io:format ("Key4", []),
{next_state, packetsDeliver , Data}.
我尝试了几件事都没有成功,我认为写作
{next_state, packetsDeliver , Data}.
会给我状态:
packetsDeliver(enter, _OldState, Data)
但是我得到了这个错误:
exception exit: {bad_return_from_state_function,
{next_state,packetsDeliver,{1}}}
in function gen_statem:loop_event_result/9 (gen_statem.erl, line 1165)
in call from proc_lib:init_p_do_apply/3 (proc_lib.erl, line 247)
3>
=ERROR REPORT==== 27-Jul-2019::23:53:35 ===
** State machine test terminating
** Last event = {cast,1}
** When server state = {allPacketsDelivered,{1}}
** Reason for termination = error:{bad_return_from_state_function,
{next_state,packetsDeliver,{1}}}
** Callback mode = [state_functions,state_enter]
** Stacktrace =
** [{gen_statem,loop_event_result,9,[{file,"gen_statem.erl"},{line,1165}]},
{proc_lib,init_p_do_apply,3,[{file,"proc_lib.erl"},{line,247}]}]
还有一个question/problem就是不知道为什么状态
packetsDeliver(enter, _OldState, Data) ->
io:format ("Key1", []),
{keep_state, Data};
正在把我送到 packetsDeliver(info, _OldState, Data)
当我做 keep_state?
看看你的州 enter
函数 returns for packetsDeliver
:
packetsDeliver(enter, _OldState, Data) ->
io:format ("Key1", []),
{keep_state, Data}; %% <====== HERE
现在看看你的州 cast
函数 returns for packetsDeliver
:
packetsDeliver(cast, _PacketData, Data) ->
io:format ("Key3", []),
{next_state, allPacketsDelivered, Data}. %% <===== HERE
现在看看你的州 enter
功能 returns for allPacketsDelivered
:
allPacketsDelivered(enter, _OldState, Data) ->
io:format ("Key4", []),
{next_state, packetsDeliver , Data}. %% <==== HERE
allpacketsDelivered
的状态 enter
函数应该 return 一个类似于 packetsDelivered
的状态 enter
函数的元组,例如{keep_state, ...}
不是 {next_state, ...}
。
从 the docs 开始,这些是状态 enter
函数允许的 return 值:
state_callback_result(ActionType) =
{keep_state, NewData :: data()} |
{keep_state,
NewData :: data(),
Actions :: [ActionType] | ActionType} |
keep_state_and_data |
{keep_state_and_data, Actions :: [ActionType] | ActionType} |
{repeat_state, NewData :: data()} |
{repeat_state,
NewData :: data(),
Actions :: [ActionType] | ActionType} |
repeat_state_and_data |
{repeat_state_and_data, Actions :: [ActionType] | ActionType} |
stop |
{stop, Reason :: term()} |
{stop, Reason :: term(), NewData :: data()} |
{stop_and_reply,
Reason :: term(),
Replies :: [reply_action()] | reply_action()} |
{stop_and_reply,
Reason :: term(),
Replies :: [reply_action()] | reply_action(),
NewData :: data()}
请注意,{next_state, ...}
不是允许的 return 值之一,这就是您收到错误 bad_return_from_state_function
的原因。 docs 还说:
When the gen_statem runs with state enter calls, these functions are
also called with arguments (enter, OldState, ...)
during every state
change. In this case there are some restrictions on the actions that
may be returned: postpone() is not allowed since a state enter call is
not an event so there is no event to postpone, and
{next_event,_,_}
is not allowed since using state enter calls should
not affect how events are consumed and produced. You may also not
change states from this call. Should you return
{next_state,NextState, ...}
with NextState =/= State
the
gen_statem crashes. Note that it is actually allowed to use
{repeat_state, NewData, ...} although it makes little sense since you
immediately will be called again with a new state enter call making
this just a weird way of looping, and there are better ways to loop in
Erlang. If you do not update NewData and have some loop termination
condition, or if you use {repeat_state_and_data, _} or
repeat_state_and_data you have an infinite loop! You are advised to
use {keep_state,...}, {keep_state_and_data,_} or keep_state_and_data
since changing states from a state enter call is not possible anyway.
======
Another question/problem is that I don't know why the state
packetsDeliver(enter, _OldState, Data) ->
io:format ("Key1", []),
{keep_state, Data};
is delivering me to packetsDeliver(info, _OldState, Data) when I do
keep_state?
when I do keep_state
是什么意思?我可以告诉你这对阅读你的问题的人意味着什么:绝对没有。
当我 do keep_state
时,该信息回调不会执行。所以这告诉你如何修复你的代码,对吧?错了。
我是这样做的:
send_event() ->
gen_statem:cast(?MODULE, hello).
如果你这样做:
Pid ! {blah, blah}
然后将执行当前状态的 info
回调。
完整示例:
-module(packets).
-behavior(gen_statem).
-compile(export_all).
start_link() ->
gen_statem:start_link({local, ?MODULE}, ?MODULE, [], []).
init([]) ->
io:format ("init~n"),
Data=1,
{ok, packetsDeliver, Data}.
%The initial state will be packetsDeliver.
%And, when you transition to a state, and you
%have specified state_enter, then the function
%State(enter, OldState, Data) will execute, which
%in this case is packetsDeliver(enter, OldState, Data)
callback_mode() ->
[state_functions, state_enter].
packetsDeliver(enter, _OldState, Data) ->
io:format("packetsDeliver enter~n"),
{keep_state, Data};
packetsDeliver(cast, _Msg, Data) ->
io:format ("packetsDeliver cast~n"),
{next_state, allPacketsDelivered, Data};
packetsDeliver(info, _Msg, Data) ->
io:format("packetsDeliver info~n"),
{keep_state, Data}.
allPacketsDelivered(enter, _OldState, _Data) ->
io:format("allPacketsDelivered enter~n"),
%{next_state, packetsDeliver , Data}.
{keep_state_and_data, []}.
send_event() ->
gen_statem:cast(?MODULE, hello).
在shell中:
~/erlang_programs/gen_statem$ erl
Erlang/OTP 20 [erts-9.3] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:10] [hipe] [kernel-poll:false]
Eshell V9.3 (abort with ^G)
1> c(packets).
packets.erl:3: Warning: export_all flag enabled - all functions will be exported
{ok,packets}
2> packets:start_link().
init
packetsDeliver enter
{ok,<0.71.0>}
3> Pid = whereis(packets).
<0.71.0>
4> Pid ! hello.
packetsDeliver info
hello
5> packets:send_event().
packetsDeliver cast
ok
allPacketsDelivered enter
6>
我遇到了一个奇怪的问题。我得到了这个FSM(代码的内容不是很无能,所以我把它去掉了,现在只能看结构了):
start_link() ->
gen_statem:start_link({local, ?MODULE}, ?MODULE, [], []).
init([]) ->
io:format ("init", []),
Data={1},
{ok, packetsDeliver, Data}.
callback_mode() ->
[state_functions, state_enter].
packetsDeliver(enter, _OldState, Data) ->
io:format ("Key1", []),
{keep_state, Data};
packetsDeliver(info, _OldState, Data) ->
io:format ("Key2", []),
{keep_state, Data};
packetsDeliver(cast, _PacketData, Data) ->
io:format ("Key3", []),
{next_state, allPacketsDelivered, Data}.
allPacketsDelivered(enter, _OldState, Data) ->
io:format ("Key4", []),
{next_state, packetsDeliver , Data}.
我尝试了几件事都没有成功,我认为写作
{next_state, packetsDeliver , Data}.
会给我状态:
packetsDeliver(enter, _OldState, Data)
但是我得到了这个错误:
exception exit: {bad_return_from_state_function,
{next_state,packetsDeliver,{1}}}
in function gen_statem:loop_event_result/9 (gen_statem.erl, line 1165)
in call from proc_lib:init_p_do_apply/3 (proc_lib.erl, line 247)
3>
=ERROR REPORT==== 27-Jul-2019::23:53:35 ===
** State machine test terminating
** Last event = {cast,1}
** When server state = {allPacketsDelivered,{1}}
** Reason for termination = error:{bad_return_from_state_function,
{next_state,packetsDeliver,{1}}}
** Callback mode = [state_functions,state_enter]
** Stacktrace =
** [{gen_statem,loop_event_result,9,[{file,"gen_statem.erl"},{line,1165}]},
{proc_lib,init_p_do_apply,3,[{file,"proc_lib.erl"},{line,247}]}]
还有一个question/problem就是不知道为什么状态
packetsDeliver(enter, _OldState, Data) ->
io:format ("Key1", []),
{keep_state, Data};
正在把我送到 packetsDeliver(info, _OldState, Data) 当我做 keep_state?
看看你的州 enter
函数 returns for packetsDeliver
:
packetsDeliver(enter, _OldState, Data) ->
io:format ("Key1", []),
{keep_state, Data}; %% <====== HERE
现在看看你的州 cast
函数 returns for packetsDeliver
:
packetsDeliver(cast, _PacketData, Data) ->
io:format ("Key3", []),
{next_state, allPacketsDelivered, Data}. %% <===== HERE
现在看看你的州 enter
功能 returns for allPacketsDelivered
:
allPacketsDelivered(enter, _OldState, Data) ->
io:format ("Key4", []),
{next_state, packetsDeliver , Data}. %% <==== HERE
allpacketsDelivered
的状态 enter
函数应该 return 一个类似于 packetsDelivered
的状态 enter
函数的元组,例如{keep_state, ...}
不是 {next_state, ...}
。
从 the docs 开始,这些是状态 enter
函数允许的 return 值:
state_callback_result(ActionType) =
{keep_state, NewData :: data()} |
{keep_state,
NewData :: data(),
Actions :: [ActionType] | ActionType} |
keep_state_and_data |
{keep_state_and_data, Actions :: [ActionType] | ActionType} |
{repeat_state, NewData :: data()} |
{repeat_state,
NewData :: data(),
Actions :: [ActionType] | ActionType} |
repeat_state_and_data |
{repeat_state_and_data, Actions :: [ActionType] | ActionType} |
stop |
{stop, Reason :: term()} |
{stop, Reason :: term(), NewData :: data()} |
{stop_and_reply,
Reason :: term(),
Replies :: [reply_action()] | reply_action()} |
{stop_and_reply,
Reason :: term(),
Replies :: [reply_action()] | reply_action(),
NewData :: data()}
请注意,{next_state, ...}
不是允许的 return 值之一,这就是您收到错误 bad_return_from_state_function
的原因。 docs 还说:
When the gen_statem runs with state enter calls, these functions are also called with arguments
(enter, OldState, ...)
during every state change. In this case there are some restrictions on the actions that may be returned: postpone() is not allowed since a state enter call is not an event so there is no event to postpone, and{next_event,_,_}
is not allowed since using state enter calls should not affect how events are consumed and produced. You may also not change states from this call. Should you return{next_state,NextState, ...}
withNextState =/= State
the gen_statem crashes. Note that it is actually allowed to use {repeat_state, NewData, ...} although it makes little sense since you immediately will be called again with a new state enter call making this just a weird way of looping, and there are better ways to loop in Erlang. If you do not update NewData and have some loop termination condition, or if you use {repeat_state_and_data, _} or repeat_state_and_data you have an infinite loop! You are advised to use {keep_state,...}, {keep_state_and_data,_} or keep_state_and_data since changing states from a state enter call is not possible anyway.
======
Another question/problem is that I don't know why the state
packetsDeliver(enter, _OldState, Data) -> io:format ("Key1", []), {keep_state, Data};
is delivering me to packetsDeliver(info, _OldState, Data) when I do keep_state?
when I do keep_state
是什么意思?我可以告诉你这对阅读你的问题的人意味着什么:绝对没有。
当我 do keep_state
时,该信息回调不会执行。所以这告诉你如何修复你的代码,对吧?错了。
我是这样做的:
send_event() ->
gen_statem:cast(?MODULE, hello).
如果你这样做:
Pid ! {blah, blah}
然后将执行当前状态的 info
回调。
完整示例:
-module(packets).
-behavior(gen_statem).
-compile(export_all).
start_link() ->
gen_statem:start_link({local, ?MODULE}, ?MODULE, [], []).
init([]) ->
io:format ("init~n"),
Data=1,
{ok, packetsDeliver, Data}.
%The initial state will be packetsDeliver.
%And, when you transition to a state, and you
%have specified state_enter, then the function
%State(enter, OldState, Data) will execute, which
%in this case is packetsDeliver(enter, OldState, Data)
callback_mode() ->
[state_functions, state_enter].
packetsDeliver(enter, _OldState, Data) ->
io:format("packetsDeliver enter~n"),
{keep_state, Data};
packetsDeliver(cast, _Msg, Data) ->
io:format ("packetsDeliver cast~n"),
{next_state, allPacketsDelivered, Data};
packetsDeliver(info, _Msg, Data) ->
io:format("packetsDeliver info~n"),
{keep_state, Data}.
allPacketsDelivered(enter, _OldState, _Data) ->
io:format("allPacketsDelivered enter~n"),
%{next_state, packetsDeliver , Data}.
{keep_state_and_data, []}.
send_event() ->
gen_statem:cast(?MODULE, hello).
在shell中:
~/erlang_programs/gen_statem$ erl
Erlang/OTP 20 [erts-9.3] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:10] [hipe] [kernel-poll:false]
Eshell V9.3 (abort with ^G)
1> c(packets).
packets.erl:3: Warning: export_all flag enabled - all functions will be exported
{ok,packets}
2> packets:start_link().
init
packetsDeliver enter
{ok,<0.71.0>}
3> Pid = whereis(packets).
<0.71.0>
4> Pid ! hello.
packetsDeliver info
hello
5> packets:send_event().
packetsDeliver cast
ok
allPacketsDelivered enter
6>