先自我介绍一下,小编浙江大学毕业,去过华为、字节跳动等大厂,目前阿里P7
深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年最新Golang全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Go语言开发知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新
如果你需要这些资料,可以添加V获取:vip1024b (备注go)
正文
void bomb2_dispatch(EVT_TYPE evt , void* param)
{
fp_state s = NULL;
if(evt > MAX_EVT)
{
LOG(“EVT type error!”);
return;
}
s = bomb2.state_table[bomb2.state * MAX_EVT + evt];
if(s != NULL)
{
s(evt , param);
}
}
/列出所有的状态对应的事件处理函数/
void setting_UP(EVT_TYPE evt, void* param)
{
if(bomb1.timeout< 60) ++bomb1.timeout;
bsp_display(bomb1.timeout);
}
缺点:函数粒度太小是最明显的一个缺点,一个状态和一个事件就会产生一个函数,当状态和事件较多时,处理函数将增加很快,在阅读代码时,逻辑分散。没有实现进入退出动作。
一维状态转换表
实现原理:
typedef void (fp_action)(EVT_TYPE evt,void param);
/转换表基础结构/
struct tran_evt_t
{
EVT_TYPE evt;
uint8_t next_state;
};
/状态的描述/
struct fsm_state_t
{
fp_action enter_action; //进入动作
fp_action exit_action; //退出动作
fp_action action;
tran_evt_t* tran; //转换表
uint8_t tran_nb; //转换表的大小
const char* name;
}
/状态表本体/
#define ARRAY(x) x,sizeof(x)/sizeof(x[0])
const struct fsm_state_t state_table[]=
{
{setting_enter , setting_exit , setting_action , ARRAY(set_tran_evt),“setting” },
{timing_enter , timing_exit , timing_action , ARRAY(time_tran_evt),“timing” }
};
/构建一个状态机/
struct fsm
{
const struct state_t * state_table; /* the State-Table /
uint8_t cur_state; / the current active state */
uint8_t timeout;
uint8_t code;
uint8_t defuse_code;
}bomb3;
/初始化状态机/
void bomb3_init(void)
{
bomb3.state_table = state_table; //指向状态表
bomb3.cur_state = setting;
bomb3.defuse_code = 8; //1000
}
/状态机事件派发/
void fsm_dispatch(EVT_TYPE evt , void* param)
{
tran_evt_t* p_tran = NULL;
/获取当前状态的转换表/
p_tran = bomb3.state_table[bomb3.cur_state]->tran;
/判断所有可能的转换是否与当前触发的事件匹配/
for(uint8_t i=0;i<x;i++)
{
if(p_tran[i]->evt == evt)//事件会触发转换
{
if(NULL != bomb3.state_table[bomb3.cur_state].exit_action){
bomb3.state_table[bomb3.cur_state].exit_action(NULL); //执行退出动作
}
if(bomb3.state_table[_tran[i]->next_state].enter_action){
bomb3.state_table[_tran[i]->next_state].enter_action(NULL);//执行进入动作
}
/更新当前状态/
bomb3.cur_state = p_tran[i]->next_state;
}
else
{
bomb3.state_table[bomb3.cur_state].action(evt,param);
}
}
}
/*************************************************************************
setting状态相关
***********************************************************************/
void setting_enter(EVT_TYPE evt , void param)
{
}
void setting_exit(EVT_TYPE evt , void* param)
{
}
void setting_action(EVT_TYPE evt , void* param)
{
}
tran_evt_t set_tran_evt[]=
{
{ARM , timing},
}
/timing 状态相关/
优点:
- 各个状态面向用户相对独立,增加事件和状态不需要去修改先前已存在的状态事件函数。
- 实现了状态的进入和退出
- 容易根据状态跃迁图来设计 (状态跃迁图列出了每个状态的跃迁可能,也就是这里的转换表)
- 实现灵活,可实现复杂逻辑,如上一次状态,增加监护条件来减少事件的数量。可实现非完全事件驱动
缺点:
- 函数粒度较小(比二维小且增长慢),可以看到,每一个状态需要至少3个函数,还需要列出所有的转换关系。
5. QP嵌入式实时框架
事件驱动型编程
好莱坞原则:和传统的顺序式编程方法例如“超级循环”,或传统的RTOS 的任务不同。绝大多数的现代事件驱动型系统根据好莱坞原则被构造(Don’t call me; I’ll call you.)
面向对象
类和单一继承:
工具
QM :一个通过UML类图来描述状态机的软件,并且可以自动生成C代码
QS软件追踪工具:
6. QEP实现有限状态机Fsm
/* qevent.h ----------------------------------------------------------------/
typedef struct QEventTag
{
QSignal sig;
uint8_t dynamic_;
} QEvent;
/ qep.h -------------------------------------------------------------------/
typedef uint8_t QState; / status returned from a state-handler function */
typedef QState (*QStateHandler) (void *me, QEvent const e); / argument list /
typedef struct QFsmTag / Finite State Machine /
{
QStateHandler state; / current active state */
}QFsm;
#define QFsm_ctor(me_, initial_) ((me_)->state = (initial_))
void QFsm_init (QFsm *me, QEvent const *e);
void QFsm_dispatch(QFsm *me, QEvent const *e);
#define Q_RET_HANDLED ((QState)0)
#define Q_RET_IGNORED ((QState)1)
#define Q_RET_TRAN ((QState)2)
#define Q_HANDLED() (Q_RET_HANDLED)
#define Q_IGNORED() (Q_RET_IGNORED)
#define Q_TRAN(target_) (((QFsm *)me)->state = (QStateHandler) (target_),Q_RET_TRAN)
enum QReservedSignals
{
Q_ENTRY_SIG = 1,
Q_EXIT_SIG,
Q_INIT_SIG,
Q_USER_SIG
};
/* file qfsm_ini.c ---------------------------------------------------------/
#include “qep_port.h” / the port of the QEP event processor /
#include “qassert.h” / embedded systems-friendly assertions */
void QFsm_init(QFsm *me, QEvent const *e)
{
(me->state)(me, e); / execute the top-most initial transition /
/ enter the target /
(void)(me->state)(me , &QEP_reservedEvt_[Q_ENTRY_SIG]);
}
/ file qfsm_dis.c ---------------------------------------------------------/
void QFsm_dispatch(QFsm *me, QEvent const e)
{
QStateHandler s = me->state; / save the current state */
QState r = (s)(me, e); / call the event handler /
if (r == Q_RET_TRAN) / transition taken? */
{
(void)(s)(me, &QEP_reservedEvt_[Q_EXIT_SIG]); / exit the source */
(void)(me->state)(me, &QEP_reservedEvt_[Q_ENTRY_SIG]);/enter target/
}
}
实现上面定时器例子
#include “qep_port.h” / the port of the QEP event processor /
#include “bsp.h” / board support package */
enum BombSignals /* all signals for the Bomb FSM /
{
UP_SIG = Q_USER_SIG,
DOWN_SIG,
ARM_SIG,
TICK_SIG
};
typedef struct TickEvtTag
{
QEvent super; / derive from the QEvent structure /
uint8_t fine_time; / the fine 1/10 s counter */
}TickEvt;
typedef struct Bomb4Tag
{
QFsm super; /* derive from QFsm /
uint8_t timeout; / number of seconds till explosion /
uint8_t code; / currently entered code to disarm the bomb /
uint8_t defuse; / secret defuse code to disarm the bomb */
} Bomb4;
void Bomb4_ctor (Bomb4 *me, uint8_t defuse);
QState Bomb4_initial(Bomb4 *me, QEvent const e);
QState Bomb4_setting(Bomb4 me, QEvent const e);
QState Bomb4_timing (Bomb4 me, QEvent const e);
/--------------------------------------------------------------------------/
/ the initial value of the timeout /
#define INIT_TIMEOUT 10
/…/
void Bomb4_ctor(Bomb4 me, uint8_t defuse) {
QFsm_ctor_(&me->super, (QStateHandler)&Bomb4_initial);
me->defuse = defuse; / the defuse code is assigned at instantiation /
}
/…/
QState Bomb4_initial(Bomb4 me, QEvent const e) {
(void)e;
me->timeout = INIT_TIMEOUT;
return Q_TRAN(&Bomb4_setting);
}
/…/
QState Bomb4_setting(Bomb4 me, QEvent const e) {
switch (e->sig){
case UP_SIG:{
if (me->timeout < 60) {
++me->timeout;
BSP_display(me->timeout);
}
return Q_HANDLED();
}
case DOWN_SIG: {
if (me->timeout > 1) {
–me->timeout;
BSP_display(me->timeout);
}
return Q_HANDLED();
}
case ARM_SIG: {
return Q_TRAN(&Bomb4_timing); / transition to “timing” /
}
}
return Q_IGNORED();
}
/…/
void Bomb4_timing(Bomb4 *me, QEvent const e) {
switch (e->sig) {
case Q_ENTRY_SIG: {
me->code = 0; / clear the defuse code */
return Q_HANDLED();
}
case UP_SIG: {
me->code <<= 1;
me->code |= 1;
return Q_HANDLED();
}
case DOWN_SIG: {
me->code <<= 1;
return Q_HANDLED();
}
case ARM_SIG: {
if (me->code == me->defuse) {
return Q_TRAN(&Bomb4_setting);
}
return Q_HANDLED();
}
case TICK_SIG: {
if (((TickEvt const )e)->fine_time == 0) {
–me->timeout;
BSP_display(me->timeout);
if (me->timeout == 0) {
BSP_boom(); / destroy the bomb */
}
}
return Q_HANDLED();
}
}
return Q_IGNORED();
}
优点:
- 采用面向对象的设计方法,很好的移植性
- 实现了进入退出动作
- 合适的粒度,且事件的粒度可控
- 状态切换时通过改变指针,效率高
- 可扩展成为层次状态机
缺点:
- 对事件的定义以及事件粒度的控制是设计的最大难点,如串口接收到一帧数据,这些变量的更新单独作为某个事件,还是串口收到数据作为一个事件。再或者显示屏,如果使用此种编程方式,如何设计事件。
7. QP实现层次状态机
初始化层次状态机的实现:在初始化时,用户所选取的状态永远是最底层的状态,如上图,我们在计算器开机后,应该进入的是开始状态,这就涉及到一个问题,由最初top(顶状态)到begin 是有一条状态切换路径的,当我们设置状态为begin如何搜索这条路径成为关键(知道了路径才能正确的进入begin,要执行路径中过渡状态的进入和退出事件)。
void QHsm_init(QHsm *me, QEvent const *e)
{
Q_ALLEGE((me->state)(me, e) == Q_RET_TRAN);
t = (QStateHandler)&QHsm_top; / HSM starts in the top state /
do { / drill into the target… /
QStateHandler path[QEP_MAX_NEST_DEPTH_];
int8_t ip = (int8_t)0; / transition entry path index /
path[0] = me->state; / 这里的状态为begin */
/通过执行空信号,从底层状态找到顶状态的路径/
(void)QEP_TRIG_(me->state, QEP_EMPTY_SIG_);
while (me->state != t) {
path[++ip] = me->state;
(void)QEP_TRIG_(me->state, QEP_EMPTY_SIG_);
}
/切换为begin/
me->state = path[0]; /* restore the target of the initial tran. /
/ 钻到最底层的状态,执行路径中的所有进入事件 /
Q_ASSERT(ip < (int8_t)QEP_MAX_NEST_DEPTH_);
do { / retrace the entry path in reverse (desired) order… /
QEP_ENTER_(path[ip]); / enter path[ip] */
} while ((–ip) >= (int8_t)0);
t = path[0]; /* current state becomes the new source */
} while (QEP_TRIG_(t, Q_INIT_SIG) == Q_RET_TRAN);
me->state = t;
}
状态切换:
/…/
QState result(Calc me, QEvent const e)
{
switch (e->sig)
{you
case ENTER_SIG:{
break;
}
case EXIT_SIG:{
break;
}
case C_SIG:
{
printf(“clear”);
return Q_HANDLED();
}
case B_SIG:
{
return Q_TRAN(&begin);
}
}
return Q_SUPER(&reday);
}
/.ready为result和begin的超状态…/
QState ready(Calc *me, QEvent const *e)
{
switch (e->sig)
{
case ENTER_SIG:{
break;
}
case EXIT_SIG:{
break;
}
case OPER_SIG:
{
return Q_TRAN(&opEntered);
}
}
return Q_SUPER(&on);
}
void QHsm_dispatch(QHsm *me, QEvent const *e)
{
QStateHandler path[QEP_MAX_NEST_DEPTH_];
QStateHandler s;
QStateHandler t;
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
需要这份系统化的资料的朋友,可以添加V获取:vip1024b (备注Go)
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
case OPER_SIG:
{
return Q_TRAN(&opEntered);
}
}
return Q_SUPER(&on);
}
void QHsm_dispatch(QHsm *me, QEvent const *e)
{
QStateHandler path[QEP_MAX_NEST_DEPTH_];
QStateHandler s;
QStateHandler t;
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
需要这份系统化的资料的朋友,可以添加V获取:vip1024b (备注Go)
[外链图片转存中…(img-USqIHwFe-1713544819400)]
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!