大分迷ってしまったのでメモ。
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
}
これでいいのか?わからん!でもとりあえず動いた!