This is a creation in Article, where the information may have evolved or changed.
For Erlang's finite state machine, refer to Erlang's four behaviour two-GEN_FSM this article.
Finite state machines can be expressed by the following formula
State (s) x Event (E), and Actions (A), state (S ')
These two days is just idle, with Golang realized a bit, say not much, directly on the code
Package Utilimport ("errors" "Reflect" "Sync" "Time" "Unicode" "Unicode/utf8" "Util/log") var typeoferror = reflect. TypeOf ((*error) (nil)). Elem () type FSM struct {sync. Mutexstopreason STRINGRCVR reflect. Value//Receiver of methods for the Servicetyp reflect. Type//Type of the Receivermethod map[string]reflect. Methodevent Chan Eventquit Chan intstate stringstopped bool}type event struct {event Stringparam in Terface{}timeout Int}func (FSM *FSM) IsStopped () bool {FSM. Lock () defer FSM. Unlock () return Fsm.stopped}func (FSM *FSM) sendevent (event string, param interface{}) {FSM. Lock () defer FSM. Unlock () If fsm.stopped {return}fsm.event <-event{event, param, 0}}func (FSM *FSM) Init (start string) Error {If _, OK: = Fsm.method[start];!ok {return errors. New ("Not Found-state")}fsm.state = Startgo func () {for {select {case e: = <-fsm.event:go FSM. Callstate (e) Case <-fsm.quit:goto Close}}close:close (fsm.event) Close (Fsm.quit)} () return Nil}func (FSM *FSM) callstAte (e Event) {FSM. Lock () defer FSM. Unlock () If function, OK: = Fsm.method[fsm.state]; OK {returnvalues: = function. Func.call ([]reflect. VALUE{FSM.RCVR, reflect. ValueOf (e.event), reflect. ValueOf (E.param), reflect. ValueOf (E.timeout)}) Nextstate: = Returnvalues[0]. String () Timeout: = Returnvalues[1]. Int () Errinter: = Returnvalues[2]. Interface () ErrMsg: = "" if errinter! = Nil {errmsg = Errinter. ( Error). Error ()}if nextstate = = "Stop" {FSM. Stop (errmsg) fsm.quit <-1return}if errmsg! = "" {log. LogError (errmsg)}fsm.state = Nextstateif Timeout > 0 {go FSM. Delaycall (time. Duration (timeout))}}}func (FSM *FSM) Delaycall (timeout time. Duration) {select {case <-time. After (timeout * time. Millisecond): fsm.event <-event{"Timeout", 0, int (timeout)}}}func (FSM *FSM) Stop (message string) {FSM. Stopreason = messagefsm.stopped = True}func (FSM *FSM) Close () {FSM. Lock () defer FSM. Unlock () If fsm.stopped {return}fsm.quit <-1}func NEWFSM (FSM interface{}) *FSM {f: = &fsm{typ:reflect. TypeOf (FSM), RCVR:Reflect. ValueOf (FSM), Event:make (Chan event), Quit:make (chan int)}f.method = Suitablemethods (F.typ, True) return F}func Isexport Ed (name string) bool {Rune, _: = UTF8. Decoderuneinstring (name) return Unicode. Isupper (rune)}func suitablemethods (Typ reflect. Type, reporterr bool) map[string]reflect. Method {methods: = Make (Map[string]reflect. Method) for M: = 0; M < Typ. Nummethod (); m++ {method: = Typ. Method (m) Mtype: = method. Typemname: = method. Nameif!isexported (mname) {continue}//Method needs four ins:receiver, string, interface{}, Int.if mtype. Numin ()! = 4 {if Reporterr {log. LogError ("Method", Mname, "has wrong number of ins:", Mtype. Numin ())}continue}//first Arg must be a string.if mtype. In (1). Kind ()! = reflect. String {if Reporterr {log. LogError ("Method", Mname, "arg1 type not a string:", Mtype. In (1). Kind ())}continue}//Second Arg must be a interface.if mtype. In (2). Kind ()! = reflect. Interface {if Reporterr {log. LogError ("Method", Mname, "arg2 type not a interface:", Mtype. In (2). Kind ())}continue}//Third Arg must be a int.if mtype. In (3). Kind ()! = reflect. Int {if Reporterr {log. LogError ("Method", Mname, "arg3 type not a int:", mtype. In (3). Kind ())}continue}//Method needs three out.if mtype. Numout ()! = 3 {if Reporterr {log. LogError ("Method", Mname, "has wrong number of outs:", Mtype. Numout ())}continue}if mtype. Out (0). Kind ()! = reflect. String {if Reporterr {log. LogError ("Method", Mname, "out1 type not a string:", Mtype. Out (0). Kind ())}continue}if mtype. Out (1). Kind ()! = reflect. Int {if Reporterr {log. LogError ("Method", Mname, "out1 type not a int:", mtype. Out (1). Kind ())}continue}if mtype. Out (2)! = Typeoferror {if Reporterr {log. LogError ("Method", Mname, "out3 type not a" error: ", Mtype. In (2). Kind ())}continue}methods[mname] = Method}return Methods}
Here's how to use it:
Type GOFSM struct {}func (f *GOFSM) State1 (event string, param interface{}, T int) (Nextstate string, timeout int, err err OR) {log. LogMessage (event, Param.) ( int)) return "State2", +, nil//If timeout is greater than 0, the next state is automatically called after timeout milliseconds, and the next state event is Timeout}func (f *GOFSM) State2 (event String, param interface{}, T int) (Nextstate string, timeout int, err error) {log. LogMessage (event) return "Stop", 0, errors. New ("Stop OK")//nextstate=stop stops the state machine, and err is the stop Reason}func main () {f: = util. NEWFSM (&gofsm{}) f.init ("State1") //initial state F. Sendevent ("Do", 1)//Send event time. Sleep (time. Second * 1)}
All state callback functions must start with a capital letter and the prototype must be
The event is the name of the events, Param is the argument for the event, and T>0 indicates that this is a delay event. Return value: Nextstate is the new state, must have the same name as the state callback function, and if "stop" means there is no subsequent state, the state machine stops. Timeout>0 represents a delay callback, which generates a timeout event after the timeout time.