たぶん、有識者では常識なんだろうけれども、最近まで認識できていなかった件についてのポエム
type T struct { // : } func (t *T) Method(){ // : } var t T
と定義されている場合、
var f func() = t.Method
という代入が可能。これの何が嬉しいのかというと、コールバック関数を渡さないといけない時に、具体的な値をあわせて引き渡すことが可能だという点。
昔の自分はそういうのを知らなかったので、呼び出し元で context.WithValue で引き渡すべき値を context.Context に添付し、コールバック関数側は context.Value で引き出すという方法を使っていた。それが悪いというわけではないが、本来静的チェックできるものを動的にチェックとなるので、まれに漏れがあって実行時エラーになったりする。
実際、nyagos にそういうコードが残ってたので、ちょっとそういうの、ちょっとずつ直してる。
( nyagos は Lua 依存のところと、Lua 非依存のところを明確に分けているので、コールバック関数を設定するところで、Lua 引数を想定させていない箇所も多いのだ )
旧コード
type luaKeyT struct{} var luaKey luaKeyT // コールバック関数側 func onCommandNotFound(ctx context.Context, sh *shell.Cmd, err error) error { L, ok := ctx.Value(luaKey).(Lua) if !ok { return errors.New("could get lua instance(on_command_not_found)") } // : 中略 } // コールバック関数を設定する側 shell.OnCommandNotFound = onCommandNotFound
新コード
type _LuaCallBack struct { Lua } // コールバック関数側 func (this *_LuaCallBack) onCommandNotFound(ctx context.Context, sh *shell.Cmd, err error) error { L := this.Lua // : 中略 } // コールバック関数を設定する側 shell.OnCommandNotFound = (&_LuaCallBack{Lua: L}).onCommandNotFound
これ、設定漏れがあると could get lua instance(on_command_not_found)
という実行時エラーになるんだけど、実際、発生するケースが見付かったりした。
context.WithValue は便利そうに見えて使用事例が意外とないのは、こんな風な値の引き渡し方法が既にあるから、使うケースがレアであるべき…ということがあるのかもしれないなぁ。