中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Go語言中的有限狀態機FSM怎么使用

發布時間:2023-04-26 17:08:45 來源:億速云 閱讀:154 作者:iii 欄目:開發技術

本文小編為大家詳細介紹“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怎么使用

Event(事件)是指觸發狀態轉換的輸入信號或條件。它可以是任何類型的輸入,例如傳感器數據、用戶輸入、網絡消息等。在編程中,Event通常是一個枚舉類型,每個枚舉值代表一個特定的事件。

State(狀態)是指系統在某一時刻所處的狀態,它是系統的一種抽象描述。在有限狀態機中,狀態是由一組狀態變量來描述的,這些狀態變量的取值決定了系統的狀態。狀態可以是離散的,也可以是連續的。在有限狀態機中,狀態通常用一個圓圈來表示,圓圈內部寫上狀態的名稱。例如,一個簡單的有限狀態機可以有兩個狀態:開和關,它們可以用以下方式表示:

Go語言中的有限狀態機FSM怎么使用

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怎么使用

2.2.2 簡寫版的Callbacks執行順序

Go語言中的有限狀態機FSM怎么使用

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 

讀到這里,這篇“Go語言中的有限狀態機FSM怎么使用”文章已經介紹完畢,想要掌握這篇文章的知識點還需要大家自己動手實踐使用過才能領會,如果想了解更多相關內容的文章,歡迎關注億速云行業資訊頻道。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

颍上县| 深泽县| 旅游| 蕉岭县| 剑河县| 屯昌县| 仲巴县| 桂阳县| 延寿县| 沙雅县| 南川市| 濮阳县| 博客| 玉山县| 新和县| 新乡县| 纳雍县| 图片| 合肥市| 泸溪县| 浪卡子县| 四子王旗| 繁昌县| 女性| 江川县| 九龙县| 兴业县| 平原县| 崇义县| 靖江市| 达尔| 新兴县| 克东县| 咸阳市| 夏邑县| 西贡区| 五华县| 东城区| 驻马店市| 临安市| 安乡县|