Go言語でとあるinterface型の何かが特定の関数を持ってるかを調べる
というタイトル的に お前は何を行っているんだ?
と言われそうです.
まぁ私もどう日本語で表現すればいいのだろうかってなったので例を示しましょう.
例えば次のような実装があったとします.
func f() io.Reader {
return 何らかのreader interfaceを満たしたやつ
}
golangで io.Reader
といったinterfaceはとても有名で様々な場所で利用されています.
例えば os.File
や bytes.Buffer
などの構造体などが io.Reader
をみたしたものに当たります.
io.Reader
の定義は次のようになっています.
type Reader interface {
Read(p []byte) (n int, err error)
}
つまり構造体が Read(p []byte) (n int, err error)
みたいな関数を持っていればいいわけですね.
ここで一つ問題です.
os.File
は利用したあと Close()
関数をよんで開放してあげる必要があります.
type io.Reader
だと Close()
を呼び出すことができません.
さてどのように解決しましょうか?
予め入ってる型のパターンが決まっている場合は簡単です.
何も考えずに型アサーションか型switchすればいけます.
type hasClose stuct {}
func (h *hasClose) Read(p []byte)(int, error){
return 0, nil
}
func (h *hasClose) Close() error {
return nil
}
type doesNotHaveClose struct{}
func (d *doesNotHaveClose) Read(p []byte)(int, error){
return 0, nil
}
func newReader() io.Reader {
now := time.Now()
if now.UnixNano() % 2 == 0 {
return &hasClose{}
}
return &doesNotHaveClose()
}
func main() {
r := newReader()
h, ok := r.(*hasClose)
if ok {
h.Close()
}
}
だがしかしわからないときもある.
その時は目的の関数を持つようなinterfaceを定義してあげてその方に対して型アサーションが通るかどうかで判定すれば良い.
type hasCloseInterface {
Close() error
}
func newReader() io.Reader {
return なんか適当なReaderを返す
}
func main() {
r := newReader()
h, ok := r.(hasCloseInterface)
if ok {
h.Close()
}
}
サンプルをおいておく 型アサーションサンプル