これは何?
Go のキャストが難しいなと思う事例があったので紹介する。
事例
ちょっと長いけど、まあソースコード。
go
package main
import "log"
type hoge interface {
foo() string
}
type fuga struct {
hoge
}
type piyo struct{}
func (h *piyo) foo() string {
return "piyo"
}
func main() {
f := &fuga{hoge: &piyo{}}
test := func(h hoge) {
p, ok := h.(*piyo)
log.Println(h.foo(), p, ok)
}
test(f) //=> piyo <nil> false
test(f.hoge) //=> piyo &{} true
}
このコードの
go
log.Println(h.foo(), p, ok)
の部分。
h.foo()
が func (h *piyo) foo() string
を呼べてるんだから、 h
から piyo
へのポインタって取れそうなもんだと思うんだけど、 test(f)
の中だと h.(*piyo)
が失敗する。
詳細な言語仕様を把握してないんでなんでキャストできないのかはわからないんだけど、難しいね。
var h hoge = &fuga{hoge: &piyo{}}
という形で手に入れた h
から piyo
へのポインタを手に入れるいい方法がよくわからない。
go
ppiyo, isPiyo := func(h hoge) (*piyo, bool) {
if f, fok := h.(*fuga); fok {
if p, pok := f.hoge.(*piyo); pok {
return p, true
}
}
return nil, false
}(h)
とやれば取れるけど、こんなに書かないとだめ?
まあ一般論としてはキャストが不要な設計が良い設計だと思うので、そんなことが必要な場面を作らないのが正義だとは思う。