Go中的有限状态机FSM的详细介绍 _

这篇具有很好参考价值的文章主要介绍了Go中的有限状态机FSM的详细介绍 _。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1、FSM简介

1.1 有限状态机的定义

有限状态机(Finite State Machine,FSM)是一种数学模型,用于描述系统在不同状态下的行为和转移条件。

状态机有三个组成部分:状态(State)、事件(Event)、动作(Action),事件(转移条件)触发状态的转移和动作的执行。动作的执行不是必须的,可以只转移状态,不指定任何动作。总体而言,状态机是一种用以表示有限个状态以及这些状态之间的转移和动作的执行等行为的数学模型。

状态机可以用公式 State(S) , Event(E) -> Actions (A), State(S’)表示,即在处于状态S的情况下,接收到了事件E,使得状态转移到了S’,同时伴随着动作A的执行。

Go中的有限状态机FSM的详细介绍 _,golang,开发语言,后端

Event(事件)是指触发状态转换的输入信号或条件。它可以是任何类型的输入,例如传感器数据、用户输入、网络消息等。在编程中,Event通常是一个枚举类型,每个枚举值代表一个特定的事件。

State(状态)是指系统在某一时刻所处的状态,它是系统的一种抽象描述。在有限状态机中,状态是由一组状态变量来描述的,这些状态变量的取值决定了系统的状态。状态可以是离散的,也可以是连续的。在有限状态机中,状态通常用一个圆圈来表示,圆圈内部写上状态的名称。例如,一个简单的有限状态机可以有两个状态:开和关,它们可以用以下方式表示:

Go中的有限状态机FSM的详细介绍 _,golang,开发语言,后端

Action(动作)是指在状态转移时执行的操作或动作。当有限状态机从一个状态转移到另一个状态时,可以执行一个或多个action来改变系统的状态或执行某些操作。例如,当有限状态机从“待机”状态转移到“运行”状态时,可以执行一个action来启动系统。在实际应用中,action可以是任何有效的代码,例如函数调用、变量赋值、打印输出等。

FSM 通常用于编程中,用于实现状态转移和控制流程。

注意:

在任何时刻,FSM 只能处于一种状态。

1.2 Go中的FSM

通过上面关于有限状态机的定义,我们大概知道了状态机是个什么东西,那么Golang中是怎么实现的呢。不用慌,已经有大佬实现好了,只管用就好了。

安装:

go get github.com/looplab/fsm@v1.0.1

接下来一起看看github.com/looplab/fsm 是如何使用的。

2、github.com/looplab/fsm 如何使用

注意:

不同版本的 fsm 使用方式,可能不太一样,最好是看下 NewFSM 函数的注释,看下具体的细节。 本篇文章以:github.com/looplab/fsm@v1.0.1 为例。

2.1 fsm 基础使用

这里把官方的例子改了下,感觉官方的例子不是很清晰。代码如下:

package main

import (
	"context"
	"fmt"

	"github.com/looplab/fsm"
)

type Door struct {
	Name  string
	FSM *fsm.FSM
}

func NewDoor(name string) *Door {
	d := &Door{
		Name: name,
	}

	d.FSM = fsm.NewFSM(
		"closed",
		fsm.Events{
			{Name: "open", Src: []string{"closed"}, Dst: "open"},
			{Name: "close", Src: []string{"open"}, Dst: "closed"},
		},
		fsm.Callbacks{
			"enter_state": func(_ context.Context, e *fsm.Event) { d.enterState(e) },
		},
	)

	return d
}

func (d *Door) enterState(e *fsm.Event) {
	fmt.Printf("The door's name:%s , current state:%s\n", d.Name, e.Dst)
}

func main() {
	door := NewDoor("测试")

	fmt.Printf("fsm current state: %s \n", door.FSM.Current())

	err := door.FSM.Event(context.Background(), "open")
	if err != nil {
		fmt.Println(err)
	}
	fmt.Printf("fsm current state: %s \n", door.FSM.Current())

	err = door.FSM.Event(context.Background(), "close")
	if err != nil {
		fmt.Println(err)
	}
	fmt.Printf("fsm current state: %s \n", door.FSM.Current())
}

执行结果:

fsm current state: closed 
The door's name:测试 , current state:open
fsm current state: open 
The door's name:测试 , current state:closed
fsm current state: closed

这里就通过Event改变FSM中的状态。转移公式为:Src,Event -> Dst,d.enterState。大意就是接受到了输入Event,状态机的StateSrc->Dst,并且执行了Action:d.enterState。

2.2 fsm 中 Action 何时执行?

刚开始使用的时候,好奇d.enterState(e)是什么时候调用的,我们一起看看 NewFSM 中的注释就清楚了。

// NewFSM constructs a FSM from events and callbacks.
//
// The events and transitions are specified as a slice of Event structs
// specified as Events. Each Event is mapped to one or more internal
// transitions from Event.Src to Event.Dst.
// Callbacks are added as a map specified as Callbacks where the key is parsed
// as the callback event as follows, and called in the same order:
//
// 1. before_<EVENT> - called before event named <EVENT>
//
// 2. before_event - called before all events
//
// 3. leave_<OLD_STATE> - called before leaving <OLD_STATE>
//
// 4. leave_state - called before leaving all states
//
// 5. enter_<NEW_STATE> - called after entering <NEW_STATE>
//
// 6. enter_state - called after entering all states
//
// 7. after_<EVENT> - called after event named <EVENT>
//
// 8. after_event - called after all events
//
// There are also two short form versions for the most commonly used callbacks.
// They are simply the name of the event or state:
//
// 1. <NEW_STATE> - called after entering <NEW_STATE>
//
// 2. <EVENT> - called after event named <EVENT>
//
// If both a shorthand version and a full version is specified it is undefined
// which version of the callback will end up in the internal map. This is due
// to the pseudo random nature of Go maps. No checking for multiple keys is
// currently performed.

从上面我们知道了,d.enterState(e) 是在called after entering all states 时执行的。

2.2.1 完整版书写的Callbacks执行顺序

从上面的注释能知道完整版书写的Callbacks的执行顺序如下:

Go中的有限状态机FSM的详细介绍 _,golang,开发语言,后端

2.2.2 简写版的Callbacks执行顺序

Go中的有限状态机FSM的详细介绍 _,golang,开发语言,后端

2.2.3 注意事项

虽然Callbacks的写法有两种,但是不能同时使用完整版和简写版,否则最终使用那个版本是不确定的。

2.3 较为完整的例子
package main

import (
	"context"
	"fmt"

	"github.com/looplab/fsm"
)

type Door struct {
	Name  string
	FSM *fsm.FSM
}

func NewDoor(name string) *Door {
	d := &Door{
		Name: name,
	}

	d.FSM = fsm.NewFSM(
		"closed",
		fsm.Events{
			{Name: "open", Src: []string{"closed"}, Dst: "open"},
			{Name: "close", Src: []string{"open"}, Dst: "closed"},
		},
		fsm.Callbacks{
			"before_open": func(_ context.Context, e *fsm.Event) { d.beforeOpen(e) },
			"before_event": func(_ context.Context, e *fsm.Event) { d.beforeEvent(e) },
			"leave_closed": func(_ context.Context, e *fsm.Event) { d.leaveClosed(e) },
			"leave_state": func(_ context.Context, e *fsm.Event) { d.leaveState(e) },
			"enter_open": func(_ context.Context, e *fsm.Event) { d.enterOpen(e) },
			"enter_state": func(_ context.Context, e *fsm.Event) { d.enterState(e) },
			"after_open": func(_ context.Context, e *fsm.Event) { d.afterOpen(e) },
			"after_event": func(_ context.Context, e *fsm.Event) { d.afterEvent(e) },
		},
	)

	return d
}

func (d *Door) beforeOpen(e *fsm.Event) {
	fmt.Printf("beforeOpen, current state:%s, Dst:%s \n", d.FSM.Current(), e.Dst)
}

func (d *Door) beforeEvent(e *fsm.Event) {
	fmt.Printf("beforeEvent, current state:%s, Dst:%s \n", d.FSM.Current(), e.Dst)
}

func (d *Door) leaveClosed(e *fsm.Event) {
	fmt.Printf("leaveClosed, current state:%s, Dst:%s \n", d.FSM.Current(), e.Dst)
}

func (d *Door) leaveState(e *fsm.Event) {
	fmt.Printf("leaveState, current state:%s, Dst:%s \n", d.FSM.Current(), e.Dst)
}


func (d *Door) enterOpen(e *fsm.Event) {
	fmt.Printf("enterOpen, current state:%s, Dst:%s \n", d.FSM.Current(), e.Dst)
}


func (d *Door) enterState(e *fsm.Event) {
	fmt.Printf("enterState, current state:%s, Dst:%s \n", d.FSM.Current(), e.Dst)
}


func (d *Door) afterOpen(e *fsm.Event) {
	fmt.Printf("afterOpen, current state:%s, Dst:%s \n", d.FSM.Current(), e.Dst)
}

func (d *Door) afterEvent(e *fsm.Event) {
	fmt.Printf("afterEvent, current state:%s, Dst:%s \n", d.FSM.Current(), e.Dst)
}



func main() {
	door := NewDoor("测试")

	fmt.Printf("fsm current state: %s \n", door.FSM.Current())

	err := door.FSM.Event(context.Background(), "open")
	if err != nil {
		fmt.Println(err)
	}
	fmt.Printf("fsm current state: %s \n", door.FSM.Current())

	err = door.FSM.Event(context.Background(), "close")
	if err != nil {
		fmt.Println(err)
	}
	fmt.Printf("fsm current state: %s \n", door.FSM.Current())
}

执行结果:大家重点看current state何时发生的变化。 

fsm current state: closed 
beforeOpen, current state:closed, Dst:open 
beforeEvent, current state:closed, Dst:open 
leaveClosed, current state:closed, Dst:open 
leaveState, current state:closed, Dst:open 
enterOpen, current state:open, Dst:open 
enterState, current state:open, Dst:open 
afterOpen, current state:open, Dst:open 
afterEvent, current state:open, Dst:open 
fsm current state: open 
beforeEvent, current state:open, Dst:closed 
leaveState, current state:open, Dst:closed 
enterState, current state:closed, Dst:closed 
afterEvent, current state:closed, Dst:closed 
fsm current state: closed 

 文章来源地址https://www.toymoban.com/news/detail-659683.html

到了这里,关于Go中的有限状态机FSM的详细介绍 _的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 探索FSM (有限状态机)应用

    我们是袋鼠云数栈 UED 团队,致力于打造优秀的一站式数据中台产品。我们始终保持工匠精神,探索前端道路,为社区积累并传播经验价值。。 本文作者:木杪 有限状态机(FSM) 是计算机科学中的一种数学模型,可用于表示和控制系统的行为。它由一组状态以及定义在这些

    2023年04月20日
    浏览(36)
  • 如何基于FSM有限状态机实现Enemies AI

    本文简单介绍如何基于FSM有限状态机实现Enemies AI,首先定义敌人的AI逻辑:默认状态下Enemy为巡逻状态,有若干巡逻点位,Enemy在这些点位之间来回巡逻走动,同时检测Player的位置,当Player进入一定范围内时,Enemy进入寻路状态,寻路到Player位置前,进入Attacking攻击状态,当

    2023年04月09日
    浏览(39)
  • 【Golang】VsCode下开发Go语言的环境配置(超详细图文详解)

    📓推荐网站(不断完善中):个人博客 📌个人主页:个人主页 👉相关专栏:CSDN专栏、个人专栏 🏝立志赚钱,干活想躺,瞎分享的摸鱼工程师一枚 ​ 话说在前,Go语言的编码方式是 UTF-8 ,理论上你直接使用文本进行编辑也是可以的,当然为了提升我们的开发效率我们还是需

    2024年02月07日
    浏览(85)
  • 【GoLang】Go语言几种标准库介绍(三)

    前言 上一篇,我们介绍了container、crypto、database三个库,这篇我们继续介绍剩下的库 几种库 debug 库 (各种调试文件格式访问及调试功能) 在 Go 语言的标准库中,并没有一个名为 debug 的独立库。 然而,Go 提供了一系列的工具和包,用于调试和性能分析。 这些工具和包包括 d

    2024年02月03日
    浏览(49)
  • 【GoLang】Go语言几种标准库介绍(一)

    前言 随着计算机科学的迅猛发展,编程语言也在不断涌现。 在这个多样化的编程语言生态系统中,Go语言凭借其简洁、高效、并发支持等特性逐渐崭露头角。 作为一门开源的静态编程语言,Go语言自带了丰富的标准库,为开发者提供了强大的工具和功能。 本文将深入介绍G

    2024年02月04日
    浏览(65)
  • 【GoLang】Go语言几种标准库介绍(二)

    前言 上一篇,我们介绍了 bufio (buffered I/O)库和 bytes 库 ,这篇我们继续介绍剩下的库 几种库 container 库 (封装堆、列表和环形列表等容器) container 包并不是一个独立的包,而是包含了一些子包,如 container/list 、 container/heap 等,用于实现不同类型的容器数据结构。这些数据

    2024年02月04日
    浏览(61)
  • 【GoLang入门教程】Go语言几种标准库介绍(五)

    前言 上一篇,我们介绍了fmt、Go、html 三个库,这篇我们继续介绍剩下的库 几种库 image库 (常见图形格式的访问及生成) 在 Go 语言的标准库中, image 包提供了对图像的基本操作和处理功能。 这个包定义了 Image 接口和一些基本的图像类型,同时也包含了一些实现了该接口的具

    2024年02月03日
    浏览(73)
  • 【GoLang入门教程】Go语言几种标准库介绍(六)

    前言 上一篇,我们介绍了image、IO、math三个库,这篇我们继续介绍剩下的库 几种库 Net库 (网络库,支持 Socket、HTTP、邮件、RPC、SMTP 等) 在 Go 语言的标准库中, net 包提供了对网络操作的支持,包括基本的网络协议、Socket 编程、HTTP 客户端和服务器等。 net 包包含多个子包,其

    2024年02月02日
    浏览(62)
  • 【GoLang入门教程】Go语言几种标准库介绍(四)

    前言 上一篇,我们介绍了debug、encoding、flag三个库,这篇我们继续介绍剩下的库 几种库 fmt库 (格式化操作) 在 Go 语言的标准库中, fmt 包提供了格式化输入输出的功能。 这个包包括了一系列函数,用于将数据格式化为字符串( fmt.Sprintf )、输出到控制台( fmt.Print 、 fmt.Pri

    2024年02月03日
    浏览(106)
  • 【GoLang入门教程】Go语言几种标准库介绍(八)

    强烈推荐 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站:人工智能 前言 上一篇,我们介绍了plugin、reflect、regexp三个库,这篇我们继续介绍剩下的库 几种库 runtime库 ( 运行时接口) 在 Go 语言的标准库中, runtime 包

    2024年01月19日
    浏览(66)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包