gen_statem 练习

这玩意比gen_fsm好用的多,不错!

这篇写的好 https://blog.csdn.net/linhaibo/article/details/52072764 总结的详细,不过关于 handle_event_result返回这里没表达清楚,没有这个 {keep_state_and_data} 用法 只找到了{keep_state,Data}

和 {repeate_state} {repeate_state_and_data}

 

查资料http://erlang.org/doc/man/gen_statem.html弄懂了

用gen_statem完成gen_fsm一样的功能,代码简洁了很多。

 

%%%-------------------------------------------------------------------
%%% @author 
%%% @copyright (C) 2020
%%% @doc
%%%     
%%% @end 
%%% Created : 2021/3/23-19-52
%%%-------------------------------------------------------------------
-module(statem_test).
-description("statem_test").
-vsn(1).
-behaviour(gen_statem).
%% API
-export([start_link/1, init/1, callback_mode/0, handle_event/4, terminate/3, code_change/4]).

start_link(Pwd) ->
	gen_statem:start_link(?MODULE, Pwd, []).

init(Pwd) ->
	process_flag(trap_exit, true),
	{ok, lock, {[], Pwd}}.

callback_mode() ->
	%% 返回 handle_event_function 或者 state_functions
	handle_event_function.

%% gen_statem 支持两种回调模式:
%% 1. state_functions : 和gen_fsm类似,自定义函数来完成状态传递。
%% 2. handle_event_function : 使用handle_event完成状态传递,个人觉得这种模式比较好,不用定义一些乱七八糟的函数,让代码更整齐。

%% call=同步 cast=异步

%% gen_statem:call(Pid,{start}) .
%% 对应回调 handle_event(call,{start},StateName,StateData)

%% gen_statem:cast(Pid,{start}).
%% 对应回调 handle_event(cast,{start},StateName,StateData)

%% Pid ! {start} (常见socket收到消息)
%% 对应回调 handle_event(info,{start},StateName,StateData)

handle_event(info, InputPwd, lock, {OldInput,Pwd}) ->
	if
		InputPwd =:= Pwd ->
			io:format("密码正确! ~n", []),
			{next_state, open, {[], Pwd}}; %% 密码正确开门
		length(OldInput) >= 2 ->
			io:format("密码已经输错三次了,正确密码=~p. ~n", [Pwd]),
			{next_state, lock, {[], Pwd}}; %% 状态和数据都不变
		true ->
			%% 密码不正确没满足三次,历史输入存进数据
			io:format("密码错误! ~n", []),
			{next_state, lock, {[InputPwd | OldInput], Pwd}}
	end;

%%如果状态保持不变,可以使用 {keep_state,StateData}
%%这个比gen_fsm每次都调用 next_state 方便多了

handle_event(info, _Event, open, {OldInput,Pwd}) ->
	io:format("门开了,你输入的密码总共是~p ,正确密码是~p ~n",[OldInput,Pwd]),
	{keep_state,{OldInput,Pwd}}; %% 状态和数据都不变

handle_event(info, _Event, _, State) ->
	{stop, normal, State}.


terminate(_Reason, _StateName, _State) ->
	ok.

code_change(_OldVsn, OldState, StateData, _Extra) ->
	{ok, OldState, StateData}.

gen_statem的 handle_event_function 模式,这么简单谁不爱呢

9>{_,Pid}=statem_test:start_link(banana).
{ok,<0.18398.0>}
10> Pid ! hasaki.
密码错误! 
hasaki
11> Pid ! hasaki.
密码错误! 
hasaki
12> Pid ! hasaki.
密码已经输错三次了,正确密码=banana. 
hasaki
13> Pid ! hasaki.
密码错误! 
hasaki
14> Pid ! hasaki.
密码错误! 
hasaki
15> Pid ! banana.
密码正确! 
banana
16> Pid ! banana.
门开了,你输入的密码总共是[] ,正确密码是banana 
banana
17> 

 

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值