This is a creation in Article, where the information may have evolved or changed.
Before the Spring Festival, a rough look at the public account. A simple package WeChat is implemented with Golang for access to public accounts. At that time, thinking, the text of the interactive process if you want to achieve a certain logical complex process, you may need to use the state machine. Then you see this article: "State Machines in Go" (#golang). Very well timed! Translate it here, readers!
--– Translation Divider Line--–
Go (#golang) Implementation of the State machine
I've rewritten a key service component with Go instead of Python. Because the Python interpreter is not thread-safe, a global lock is used when parsing. Unlike Python, Go has built-in concurrency support and is statically compiled.
The first step is to implement a state machine. The Python version is based on the David Mertz article.
Mertz uses an object-oriented form to define a class with data and methods. His code, aside from the syntax, is no stranger to anyone with object-oriented experience in C + +, C #, and Java.
However, Go does not provide a mechanism for an internal correlation method on a particular data structure. Instead, go allows federated methods to data structures so that any method can be applied to any structure. class {methods} and struct {}; The difference between methods. )
This form is close to what Alan Kay is saying about the initial object-oriented phase.
Let's not forget this, the following is the class of the state machine I started with the GO structure:
Type machine struct { handlers map[string]func (interface{}) (String, interface{}) Startstate string Endstates Map[string]bool}
Like the definition of Mertz, handlers is a string-key-name Map,map item that holds the value of a function, can receive an "item", and returns the next state name for the strings and updated item values.
Go thinks that functions are a class citizen object, so they are stored and passed in the same way as they do in Python.
I just made some changes at the end of the status list: Mertz uses a list of strings, but because there is no way to quickly locate in the Go list, I use Map (in Go, only iterate through the entire list of strings until a match is found).
Since the prototype of the processing function is cumbersome, I have built a custom function type for it:
Type Handler func (interface{}) (String, interface{}) type machine struct { handlers Map[string]handler Startstate string endstates Map[string]bool}
The rest is the method of defining the association of the machine structure.
First define the two methods, one provides the state name associated to the handler function, and the other sets the end state:
Func (Machine *machine) addstate (HandlerName string, Handlerfn Handler) {machine . Handlers[handlername] = Handlerfn}func (machine *machine) addendstate (EndState string) {machine . Endstates[endstate] = true}
It is worth noting that since Endstates is a map (a list in the original version of Mertz), there can be multiple states for terminating the process.
The last method is used to execute the state machine, apply the appropriate handler function, and terminate when the end state is reached.
Because function collections are stored as first-class citizens in map, it is easy to find them based on their names and make calls:
Func (Machine *machine) Execute (Cargo interface{}) { If handler, present: = machine. Handlers[machine. Startstate]; Present { for { nextstate, Nextcargo: = Handler (Cargo) _, Finished: = machine. Endstates[nextstate] If finished { break } else { handler, present = machine. Handlers[nextstate] cargo = Nextcargo } } }
The only drawback is the strong type of Go, in the prototype of the processing function, you need to specify the type of the item.
Using generic interface{} as a type, all handlers need to type assert the input items so they can process any data (the test example uses floating point as the item, but it can be any data type, even a custom struct).
The full state machine has been released as a Go package.