欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

一文詳解Go語(yǔ)言中的有限狀態(tài)機(jī)FSM

 更新時(shí)間:2023年04月25日 08:32:01   作者:畫(huà)個(gè)一樣的我  
有限狀態(tài)機(jī)(Finite?State?Machine,F(xiàn)SM)是一種數(shù)學(xué)模型,用于描述系統(tǒng)在不同狀態(tài)下的行為和轉(zhuǎn)移條件。本文主要來(lái)和大家簡(jiǎn)單講講Go語(yǔ)言中的有限狀態(tài)機(jī)FSM的使用,需要的可以參考一下

1、FSM簡(jiǎn)介

1.1 有限狀態(tài)機(jī)的定義

有限狀態(tài)機(jī)(Finite State Machine,F(xiàn)SM)是一種數(shù)學(xué)模型,用于描述系統(tǒng)在不同狀態(tài)下的行為和轉(zhuǎn)移條件。

狀態(tài)機(jī)有三個(gè)組成部分:狀態(tài)(State)、事件(Event)、動(dòng)作(Action),事件(轉(zhuǎn)移條件)觸發(fā)狀態(tài)的轉(zhuǎn)移和動(dòng)作的執(zhí)行。動(dòng)作的執(zhí)行不是必須的,可以只轉(zhuǎn)移狀態(tài),不指定任何動(dòng)作??傮w而言,狀態(tài)機(jī)是一種用以表示有限個(gè)狀態(tài)以及這些狀態(tài)之間的轉(zhuǎn)移和動(dòng)作的執(zhí)行等行為的數(shù)學(xué)模型。

狀態(tài)機(jī)可以用公式State(S) , Event(E) -> Actions (A), State(S’)表示,即在處于狀態(tài)S的情況下,接收到了事件E,使得狀態(tài)轉(zhuǎn)移到了S’,同時(shí)伴隨著動(dòng)作A的執(zhí)行。

Event(事件)是指觸發(fā)狀態(tài)轉(zhuǎn)換的輸入信號(hào)或條件。它可以是任何類型的輸入,例如傳感器數(shù)據(jù)、用戶輸入、網(wǎng)絡(luò)消息等。在編程中,Event通常是一個(gè)枚舉類型,每個(gè)枚舉值代表一個(gè)特定的事件。

State(狀態(tài))是指系統(tǒng)在某一時(shí)刻所處的狀態(tài),它是系統(tǒng)的一種抽象描述。在有限狀態(tài)機(jī)中,狀態(tài)是由一組狀態(tài)變量來(lái)描述的,這些狀態(tài)變量的取值決定了系統(tǒng)的狀態(tài)。狀態(tài)可以是離散的,也可以是連續(xù)的。在有限狀態(tài)機(jī)中,狀態(tài)通常用一個(gè)圓圈來(lái)表示,圓圈內(nèi)部寫(xiě)上狀態(tài)的名稱。例如,一個(gè)簡(jiǎn)單的有限狀態(tài)機(jī)可以有兩個(gè)狀態(tài):開(kāi)和關(guān),它們可以用以下方式表示:

Action(動(dòng)作)是指在狀態(tài)轉(zhuǎn)移時(shí)執(zhí)行的操作或動(dòng)作。當(dāng)有限狀態(tài)機(jī)從一個(gè)狀態(tài)轉(zhuǎn)移到另一個(gè)狀態(tài)時(shí),可以執(zhí)行一個(gè)或多個(gè)action來(lái)改變系統(tǒng)的狀態(tài)或執(zhí)行某些操作。例如,當(dāng)有限狀態(tài)機(jī)從“待機(jī)”狀態(tài)轉(zhuǎn)移到“運(yùn)行”狀態(tài)時(shí),可以執(zhí)行一個(gè)action來(lái)啟動(dòng)系統(tǒng)。在實(shí)際應(yīng)用中,action可以是任何有效的代碼,例如函數(shù)調(diào)用、變量賦值、打印輸出等。

FSM 通常用于編程中,用于實(shí)現(xiàn)狀態(tài)轉(zhuǎn)移和控制流程。

注意:

在任何時(shí)刻,F(xiàn)SM 只能處于一種狀態(tài)。

1.2 Go中的FSM

通過(guò)上面關(guān)于有限狀態(tài)機(jī)的定義,我們大概知道了狀態(tài)機(jī)是個(gè)什么東西,那么Golang中是怎么實(shí)現(xiàn)的呢。不用慌,已經(jīng)有大佬實(shí)現(xiàn)好了,只管用就好了。

安裝:

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

接下來(lái)一起看看github.com/looplab/fsm是如何使用的。

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

注意:

不同版本的 fsm 使用方式,可能不太一樣,最好是看下 NewFSM 函數(shù)的注釋,看下具體的細(xì)節(jié)。 本篇文章以:github.com/looplab/fsm@v1.0.1 為例。

2.1 fsm 基礎(chǔ)使用

這里把官方的例子改了下,感覺(jué)官方的例子不是很清晰。代碼如下:

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("測(cè)試")

	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())
}

執(zhí)行結(jié)果:

fsm current state: closed 
The door's name:測(cè)試 , current state:open
fsm current state: open 
The door's name:測(cè)試 , current state:closed
fsm current state: closed

這里就通過(guò)Event改變FSM中的狀態(tài)。轉(zhuǎn)移公式為:Src,Event -> Dst,d.enterState。大意就是接受到了輸入Event,狀態(tài)機(jī)的StateSrc->Dst,并且執(zhí)行了Action:d.enterState。

2.2 fsm 中 Action 何時(shí)執(zhí)行

剛開(kāi)始使用的時(shí)候,好奇d.enterState(e)是什么時(shí)候調(diào)用的,我們一起看看 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 時(shí)執(zhí)行的。

2.2.1 完整版書(shū)寫(xiě)的Callbacks執(zhí)行順序

從上面的注釋能知道完整版書(shū)寫(xiě)的Callbacks的執(zhí)行順序如下:

2.2.2 簡(jiǎn)寫(xiě)版的Callbacks執(zhí)行順序

2.2.3 注意事項(xiàng)

雖然Callbacks的寫(xiě)法有兩種,但是不能同時(shí)使用完整版和簡(jiǎn)寫(xiě)版,否則最終使用那個(gè)版本是不確定的。

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("測(cè)試")

	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())
}

執(zhí)行結(jié)果:大家重點(diǎn)看current state何時(shí)發(fā)生的變化。

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 

以上就是一文詳解Go語(yǔ)言中的有限狀態(tài)機(jī)FSM的詳細(xì)內(nèi)容,更多關(guān)于Go語(yǔ)言有限狀態(tài)機(jī)FSM的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Go語(yǔ)言實(shí)現(xiàn)讀取文件的方式總結(jié)

    Go語(yǔ)言實(shí)現(xiàn)讀取文件的方式總結(jié)

    這篇文章主要為大家詳細(xì)介紹了Go語(yǔ)言實(shí)現(xiàn)讀取文件的幾個(gè)方式,文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)Go語(yǔ)言有一定的幫助,感興趣的小伙伴可以收藏一下
    2023-04-04
  • Go語(yǔ)言中你所不知道的位操作用法

    Go語(yǔ)言中你所不知道的位操作用法

    位運(yùn)算可能在平常的編程中使用的并不多,但涉及到底層優(yōu)化,一些算法及源碼可能會(huì)經(jīng)常遇見(jiàn)。下面這篇文章主要給大家介紹了關(guān)于Go語(yǔ)言中你所不知道的位操作用法的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),需要的朋友可以參考下。
    2017-12-12
  • Go 微服務(wù)開(kāi)發(fā)框架DMicro設(shè)計(jì)思路詳解

    Go 微服務(wù)開(kāi)發(fā)框架DMicro設(shè)計(jì)思路詳解

    這篇文章主要為大家介紹了Go 微服務(wù)開(kāi)發(fā)框架DMicro設(shè)計(jì)思路詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-10-10
  • 詳解Go語(yǔ)言Slice作為函數(shù)參數(shù)的使用

    詳解Go語(yǔ)言Slice作為函數(shù)參數(shù)的使用

    Slice切片在Go語(yǔ)言中實(shí)質(zhì)是一種結(jié)構(gòu)體類型,本文詳細(xì)的介紹了Go語(yǔ)言Slice作為函數(shù)參數(shù)的使用,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-07-07
  • go語(yǔ)言代碼生成器code?generator使用示例介紹

    go語(yǔ)言代碼生成器code?generator使用示例介紹

    這篇文章主要為大家介紹了go語(yǔ)言代碼生成器code?generator的使用簡(jiǎn)單介紹,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-05-05
  • Go語(yǔ)言中TCP/IP網(wǎng)絡(luò)編程的深入講解

    Go語(yǔ)言中TCP/IP網(wǎng)絡(luò)編程的深入講解

    這篇文章主要給大家介紹了關(guān)于Go語(yǔ)言中TCP/IP網(wǎng)絡(luò)編程的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2018-05-05
  • 利用Go語(yǔ)言實(shí)現(xiàn)Raft日志同步

    利用Go語(yǔ)言實(shí)現(xiàn)Raft日志同步

    這篇文章主要為大家詳細(xì)介紹了如何利用Go語(yǔ)言實(shí)現(xiàn)Raft日志同步,文中的示例代碼講解詳細(xì),對(duì)我們深入了解Go語(yǔ)言有一定的幫助,需要的可以參考一下
    2023-05-05
  • Golang中如何實(shí)現(xiàn)枚舉詳析

    Golang中如何實(shí)現(xiàn)枚舉詳析

    舉就是將數(shù)據(jù)值一一列出來(lái),枚舉可以用來(lái)表示一些固定的值,枚舉是常量組成的,下面這篇文章主要給大家介紹了關(guān)于Golang中如何實(shí)現(xiàn)枚舉的相關(guān)資料,需要的朋友可以參考下
    2022-07-07
  • Go語(yǔ)言超時(shí)退出的三種實(shí)現(xiàn)方式總結(jié)

    Go語(yǔ)言超時(shí)退出的三種實(shí)現(xiàn)方式總結(jié)

    這篇文章主要為大家詳細(xì)介紹了Go語(yǔ)言中超時(shí)退出的三種實(shí)現(xiàn)方式,文中的示例代碼簡(jiǎn)潔易懂,對(duì)我們深入了解Go語(yǔ)言有一定的幫助,需要的可以了解一下
    2023-06-06
  • go語(yǔ)言實(shí)現(xiàn)短信發(fā)送實(shí)例探究

    go語(yǔ)言實(shí)現(xiàn)短信發(fā)送實(shí)例探究

    這篇文章主要為大家介紹了go語(yǔ)言實(shí)現(xiàn)短信發(fā)送實(shí)例探究,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2024-01-01

最新評(píng)論