Skip to content

Instantly share code, notes, and snippets.

@mt-inside
Last active March 23, 2021 13:06
Show Gist options
  • Save mt-inside/05aed0179754b4cd234783e65bc648c9 to your computer and use it in GitHub Desktop.
Save mt-inside/05aed0179754b4cd234783e65bc648c9 to your computer and use it in GitHub Desktop.
Used in a blog!
package main
import "fmt"
type event int
const (
push event = iota
coin event = iota
)
type state int
const (
locked state = iota
unlocked state = iota
)
func main() {
s := locked
testEvents := []event{push, coin, push, push, coin, push, coin, coin, coin, push, push}
for _, e := range testEvents {
if s == locked {
if e == push {
sideEffect("ouch")
} else if e == coin {
sideEffect("green light")
s = unlocked
}
} else if s == unlocked {
if e == push {
sideEffect("click")
s = locked
} else if e == coin {
sideEffect("cha-ching")
}
}
}
}
func sideEffect(s string) {
fmt.Println(s)
}
package main
import "fmt"
type event int
const (
push event = iota
coin event = iota
)
type stateFn func(event) stateFn
func main() {
t := newTurnstyle()
testEvents := []event{push, coin, push, push, coin, push, coin, coin, coin, push, push}
for _, e := range testEvents {
t.dispatch(e)
}
fmt.Println("Day's takings:", t.takings)
}
type turnstyle struct {
state stateFn
takings int
}
func newTurnstyle() *turnstyle {
t := &turnstyle{takings: 0}
t.state = t.stateLocked
return t
}
func (t *turnstyle) dispatch(e event) {
next := t.state(e)
if next != nil {
t.state = next
}
}
func (t *turnstyle) stateLocked(e event) stateFn {
switch e {
case push:
sideEffect("ouch")
return nil
case coin:
sideEffect("green light")
t.takings = t.takings + 1
return t.stateUnlocked
}
panic("unknown event")
}
func (t *turnstyle) stateUnlocked(e event) stateFn {
switch e {
case push:
sideEffect("click")
return t.stateLocked
case coin:
sideEffect("cha-ching")
t.takings = t.takings + 1
return nil
}
panic("unknown event")
}
func sideEffect(s string) {
fmt.Println(s)
}
package main
import "fmt"
type event int
const (
push event = iota
coin event = iota
)
type stateFn func(event) stateFn
func main() {
/* This example is called "1-D".
* We actually store the "state" as a pointer straight to the function that implements it.
* But we could have a state enum and a slice of the funcions (see 2-D) */
s := stateLocked
testEvents := []event{push, coin, push, push, coin, push, coin, coin, coin, push, push}
for _, e := range testEvents {
s = dispatch(s, e)
}
}
func dispatch(s stateFn, e event) stateFn {
next := s(e)
if next == nil {
return s
}
return next
}
func stateLocked(e event) stateFn {
switch e {
case push:
sideEffect("ouch")
return nil
case coin:
sideEffect("green light")
return stateUnlocked
}
panic("unknown event")
}
func stateUnlocked(e event) stateFn {
switch e {
case push:
sideEffect("click")
return stateLocked
case coin:
sideEffect("cha-ching")
return nil
}
panic("unknown event")
}
func sideEffect(s string) {
fmt.Println(s)
}
package main
import "fmt"
type event int
const (
push event = iota
coin event = iota
)
type state int
const (
locked state = iota
unlocked state = iota
)
type stateFn func() (state, bool)
func main() {
t := newTurnstyle()
testEvents := []event{push, coin, push, push, coin, push, coin, coin, coin, push, push}
for _, e := range testEvents {
t.dispatch(e)
}
fmt.Println("Day's takings:", t.takings)
}
type turnstyle struct {
takings int
state state
machine [][]stateFn
/* Another way to do this would be
* - an interface specifying handler functions for each event
* - each "row", ie each state, isn't a slice of functions, but rather an object, providing all th
* - see https://golangbyexample.com/state-design-pattern-go/
*/
}
func newTurnstyle() *turnstyle {
t := &turnstyle{takings: 0, state: locked}
t.machine = [][]stateFn{
{t.lockedPush, t.lockedCoin},
{t.unlockedPush, t.unlockedCoin},
}
return t
}
func (t *turnstyle) dispatch(e event) {
fn := t.machine[t.state][e]
next, transition := fn()
if transition {
t.state = next
}
}
func (t *turnstyle) lockedPush() (state, bool) {
sideEffect("ouch")
return 0, false
}
func (t *turnstyle) lockedCoin() (state, bool) {
sideEffect("green light")
t.takings = t.takings + 1
return unlocked, true
}
func (t *turnstyle) unlockedPush() (state, bool) {
sideEffect("click")
return locked, true
}
func (t *turnstyle) unlockedCoin() (state, bool) {
sideEffect("cha-ching")
t.takings = t.takings + 1
return 0, false
}
func sideEffect(s string) {
fmt.Println(s)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment