大分迷ってしまったのでメモ。
type Foo interface { ... } type Bar struct {...} // implements Foo type Quux struct { A int B string C Foo }
これをjson.Unmarshalでデコードしようと思うとするとQuux.Cをデコードするところで「どうやってGo Valueにするのかわからん!」ってGoに文句言われた。ちなみにgo 1.5
Twitterでは例えばFooにjson.Marshalerとjson.Unmarshalerを定義しては…と言われたけど、これだとUnmarshalerは定義できない:
type Foo interface { json.Marshaler // json.Unmarshaler (Can't do this, because concrete type needs pointer receiver) } // If you uncomment the above, you get this: // cannot use Bar literal (type Bar) as type Foo in assignment: // Bar does not implement Foo (UnmarshalJSON method has pointer receiver) func (b *Bar) UnmarshalJSON(buf []byte) error { ... }
ぐはー。どういうことやねん。色々試したが、BarをJSON stringに変換するMarshalJSON()を実装した上で、文字列からBarインスタンスを作る関数を作って、Quuxをこうすることによって動くようになった:
func (q *Quux) UnmarshalJSON(buf []byte) error { var qtmp struct { A int B string C string // Foo型はstringにMarshalするようにしてあった } var err error if err = json.Unmarshal(buf, &qtmp); err != nil { return err } // うりゃ!文字列からFoo型に変換 q.C = NewConcreteFooFromName(qtmp.C) q.A = qtmp.A q.B = qtmp.B return nil }
これでいいのか?わからん!でもとりあえず動いた!