golang で event emitter/dispatcher 的なもの
golang で JS 的な addEventListener/dispatchEvent 的なことをしたいときどうするか?
emission
JS にあるようなのと全く同じ様に「イベント名」でイベントの種類を識別して任意の「イベントオブジェクト」をやりとりする。
On/Off/Once とか jQuery にあるような便利メソッドがついてる。
リフレクションで型変換は隠蔽されているが、もしリスナーとエミッターとで型が食い違っていると、実行時エラーになる。
package main
import (
"github.com/chuckpreslar/emission"
"log"
)
type ClickEvent struct {
button string
}
type KeyEvent struct {
key string
}
func main() {
emitter := emission.NewEmitter()
emitter.On("click", func (ev *ClickEvent) {
log.Printf("onclick %v", ev)
})
emitter.On("key", func (ev *KeyEvent) {
log.Printf("onkey %v", ev)
})
emitter.Emit("click", &ClickEvent{ button : "left" })
emitter.Emit("click", &ClickEvent{ button : "right" })
emitter.Emit("key", &KeyEvent{ key : "A" })
// panic
emitter.Emit("key", &ClickEvent{ button : "right" })
// or also panic
emitter.On("key", func (ev *ClickEvent) {
log.Printf("onkey2 %v", ev)
})
emitter.Emit("key", &KeyEvent{ button : "right" })
} go-pubsub
Pub/Sub/Leave というメソッドが生えている。Pub は Emit/Dispatch, Sub は addListener/On, Leave は removeListener/Off に対応する。
「イベント名」というパラメータが存在せず、型の選択によって自動的にディスパッチされる。よって型がマッチしなければリスナーは実行されないので、原理的に型変換の実行時エラーは発生しない (もし間違えた場合単に実行時になって「呼ばれない」ことに気付く)
package main
import (
"github.com/mattn/go-pubsub"
"log"
"time"
)
type ClickEvent struct {
button string
}
type KeyEvent struct {
key string
}
func main() {
ps := pubsub.New()
ps.Sub(func(ev *ClickEvent) {
log.Printf("onclick %v", ev)
})
ps.Sub(func(ev *KeyEvent) {
log.Printf("onkey %v", ev)
})
ps.Pub(&ClickEvent{button: "left"})
ps.Pub(&ClickEvent{button: "right"})
ps.Pub(&KeyEvent{key: "A"})
time.Sleep(100 * time.Millisecond)
} サンプルコード書いてて気付いたが、Sub に登録した関数は Sub を呼んだ順あるいは Pub を呼んだ順に関係なく実行されうる? (ref. 登録された関数を go で呼んでる)
下記コードのように time.Sleep の代わりに Pub/Sub によって終了を待とうとするとたまに失敗する。(完全に終了を待つ方法がわからなかった)
package main
import (
"github.com/mattn/go-pubsub"
"log"
)
type ClickEvent struct {
button string
}
type KeyEvent struct {
key string
}
func main() {
ps := pubsub.New()
ps.Sub(func(ev *ClickEvent) {
log.Printf("onclick %v", ev)
})
ps.Sub(func(ev *KeyEvent) {
log.Printf("onkey %v", ev)
})
ps.Pub(&ClickEvent{button: "left"})
ps.Pub(&ClickEvent{button: "right"})
ps.Pub(&KeyEvent{key: "A"})
// waiting for processing all messages
// -> FAIL
done := make(chan bool)
ps.Sub(func(b bool) {
ps.Close()
done <- true
})
ps.Pub(true)
<-done
} 関連エントリー
- golang で websocket websocket.JSON を使った場合 JSON をやりとりする場合専用の方法がある (JSON-RPC ライクな実装を書いてみた場合)...
- Rock64 を買って golang で赤外線受信を試してみた Rock64 http://akizukidenshi.com/catalog/g/gM-12382/ というのを買ってみた。 とりあえず ...
- NiZ Keyboard PLUM からキーマップや打鍵回数を読み出す NiZ のアプリケーションは Windows 向けしかない。プロトコルが気になったので、とりあえず打鍵回数を読み出すところをまでをやってみた...
- minimist でサブコマンド付きコマンドを実装する node.js 用のコマンドラインパーサである minimist は必要最低限かつわかりやすくていいですね。 しかもサブコマンド用のオプショ...
- mbed USBSerial を WebUSB から扱うには mbed USBDevice ライブラリの中に USB CDC で動く USBSerial クラスが実装されている。これを Web USB ...