状态机编程

本文介绍了有限状态机的工作原理,即根据事件和当前状态决定动作并设置下一状态。阐述了状态机的两种实现方法:竖着写(在状态中判断事件)和横着写(在事件中判断状态),对比了二者效果,指出横着写效果更好,但小项目为节约内存也可用竖着写。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

有限状态机的工作原理:发生事件(event)后,根据当前状态(cur_state) ,决定执行的动作(action),并设置下一个状态号(nxt_state)。

 

 
 

状态机可以用两种方法实现:竖着写(在状态中判断事件)和横着写(在事件中判断状态)。这两种实现在本质上是完全等效的,但在实际操作中,效果却截然不同。

  1. 竖着写(在状态中判断事件)C代码片段:

        cur_state = nxt_state;     

  1. switch(cur_state) //在当前状态中判断事件  
  2. {              
  3.     case s0: //在s0状态     
  4.         if(e0_event) //如果发生e0事件,那么就执行a0动作,并保持状态不变;  
  5.         {     
  6.     //执行a0动作;                 
  7.     //nxt_state = s0;  //因为状态号是自身,所以可以删除此句,以提高运行速度。  
  8.         }   
  9.         else if(e1_event) //如果发生e1事件,那么就执行a1动作,并将状态转移到s1态;  
  10.         {     
  11.             //执行a1动作;  
  12.             nxt_state = s1;  
  13.         }             
  14.         else if(e2_event) //如果发生e2事件,那么就执行a2动作,并将状态转移到s2态;  
  15.         {    
  16.             //执行a2动作;  
  17.             nxt_state = s2;  
  18.         }  
  19.         else  
  20.         {  
  21.             break;      
  22.         }     
  23.   
  24.     case s1: //在s1状态  
  25.         if(e2_event) //如果发生e2事件,那么就执行a2动作,并将状态转移到s2态;   
  26.         {                  
  27.             //执行a2动作;  
  28.          nxt_state = s2;  
  29.         }             
  30.         else  
  31.         {  
  32. break;  
  33.         }  
  34.   
  35.     case s2: //在s2状态  
  36.         if(e0_event)  //如果发生e0事件,那么就执行a0动作,并将状态转移到s0态;  
  37.         {  
  38.             //执行a0动作;                 
  39.             nxt_state = s0;  
  40.         }  
  41. }

 

  1. 横着写(在事件中判断状态)C代码片段:
  1. //e0事件发生时,执行的函数  
  2. void e0_event_function(int * nxt_state)  
  3. {     
  4.     int cur_state;     
  5.     cur_state = *nxt_state;     
  6.     switch(cur_state)  
  7.     {         
  8.         case s0: //观察表1,在e0事件发生时,s1处为空     
  9.         case s2: //执行a0动作;             
  10.         *nxt_state = s0;  
  11.     }  
  12. }  
  13.   
  14. //e1事件发生时,执行的函数  
  15. void e1_event_function(int * nxt_state)  
  16. {     
  17.     int cur_state;     
  18.     cur_state = *nxt_state;     
  19.     switch(cur_state)  
  20.     {         
  21.         case s0: //观察表1,在e1事件发生时,s1和s2处为空             
  22.             //执行a1动作;             
  23.             *nxt_state = s1;  
  24.     }  
  25. }  
  26.   
  27. //e2事件发生时,执行的函数  
  28. void e2_event_function(int * nxt_state)  
  29. {     
  30.     int cur_state;     
  31.     cur_state = *nxt_state;     
  32.     switch(cur_state)  
  33.     {         
  34.         case s0: //观察表1,在e2事件发生时,s2处为空         
  35.         case s1:             
  36.             //执行a2动作;             
  37.             *nxt_state = s2;   
  38.     }  
  39. }  

上面横竖两种写法的代码片段,实现的功能完全相同,但是,横着写的效果明显好于竖着写的效果。理由如下:

1、竖着写隐含了优先级排序(其实各个事件是同优先级的),排在前面的事件判断将毫无疑问地优先于排在后面的事件判断。这种if/else if写法上的限制将破坏事件间原有的关系。而横着写不存在此问题。

2、由于处在每个状态时的事件数目不一致,而且事件发生的时间是随机的,无法预先确定,导致竖着写沦落为顺序查询方式,结构上的缺陷使得大量时间被浪费。对于横着写,在某个时间点,状态是唯一确定的,在事件里查找状态只要使用switch语句,能一步定位到相应的状态,延迟时间可以预先准确估算。而且在事件发生时,调用事件函数,在函数里查找唯一确定的状态,并根据其执行动作和状态转移的思路清晰简洁,效率高,富有美感。

竖着写的方法也不是完全不能使用,在一些小项目里,逻辑不太复杂,功能精简,同时为了节约内存耗费,竖着写的方法也不失为一种合适的选择。

 

参考:https://blog.csdn.net/V__KING__/article/details/71740492

### date-fns 基础用法 date-fns 提供了一系列用于处理日期的基础方法,这些方法设计得非常直观易懂。为了使用 date-fns 库中的功能,首先需要安装并导入必要的函数。 #### 安装与基本导入 可以通过 npm 或 yarn 进行安装: ```bash npm install date-fns ``` 接着,在代码中按需加载特定的功能模块而非整个库,这有助于减少打包后的体积大小[^1]。 ```javascript import { format, addDays } from 'date-fns'; ``` #### 创建和格式化日期对象 创建一个新的 `Date` 实例可以直接传递给 date-fns 函数来获取当前时间戳对应的日期字符串表示形式: ```javascript const currentDate = new Date(); console.log(format(currentDate, 'yyyy-MM-dd HH:mm:ss')); // 输出形如 "2023-09-28 17:45:30" ``` 此操作利用了 `format()` 方法按照指定模式转换日期显示样式[^3]。 #### 执行简单的算术运算 对于执行加减天数的操作可以借助于 `addDays()` 等辅助工具函数完成: ```javascript // 获取三天前的日期 const threeDaysAgo = addDays(new Date(), -3); console.log(format(threeDaysAgo, 'yyyy-MM-dd')); ``` 上述例子展示了如何计算相对于今天向前推移几天的结果,并将其格式化输出。 #### 判断两个日期之间的关系 比较两个不同日期之间先后顺序或者相隔多少单位的时间差值也是常见的需求之一。这里以判断某一天是否为昨天为例说明: ```javascript import { isYesterday } from 'date-fns'; if (isYesterday(someDay)) { console.log('确实是昨天'); } ``` 同样地,也有类似的 `isToday()` 和 `isTomorrow()` 可用来做当天或明日的检测[^5]。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值