net/httpライブラリで気になる記述を見つけた
net/httpのGETを使ってレスポンス本体の内容を操作する、といったコードを書いていた時、
ふとResponse.Bodyの型を見てみるとio.ReadCloser interfaceが指定されていた。
type Response struct {
/// ~~~ 省略 ~~~
Body io.ReadCloser
/// ~~~ 省略 ~~~
}
こいつのinterface定義を見てみるとこのように定義されていた。
// 定義①
type ReadCloser interface {
Reader
Closer
}
こんな感じのinterface定義は見るけど、上記のような定義はあまり見たことがなかったのでちょっと調べてみた。
type Writer interface {
Write(p []byte) (n int, err error)
}
interfaceの埋め込みという記述らしい
先述の別interfaceを含むinterface内に出てきたReader
interfaceとCloser
interfaceはそれぞれ下記のような定義だが、
type Reader interface {
Read(p []byte) (n int, err error)
}
type Closer interface {
Close() error
}
これらを両方の実装を要求するinterfaceを定義する際に定義①のような記述ができる。
これをinterfaceの埋め込みといい、下記の記述と同等の定義となる。
type ReadCloser interface {
Read(p []byte) (n int, err error)
Close() error
}
どんな場面で活用できるか
Reader
interfaceとCloser
interfaceのような一つしか関数の実装要求をしないinterfaceならば、そのまま新しいinterface内に要求関数を記述してもいいように思えるが、簡潔な記述とメンテナンス性を考えるなら埋め込みを使ったほうがいい。
例えば、そもそもReader
interfaceとCloser
interfaceが実装要求する関数がそれぞれ複数個あると、それを全部新しいinterfaceに記述するのは冗長だし、仮に初期実装時に実装要求する関数が少なくても後々増えたときにいちいちReadCloser
interfaceに定義を追加するのは面倒くさい。
なので、埋め込みを使うことで簡潔でメンテのしやすいコードを書くことができる。
type Reader interface {
MethodA() error
MethodB() error
MethodC() error
MethodD() error
MethodE() error
MethodF() error
}
type Closer interface {
MethodG() error
MethodH() error
MethodI() error
MethodJ() error
MethodK() error
MethodL() error
}
// ReaderもCloserも実装要求するようかけるが、冗長すぎる...
type ReadCloser interface {
MethodA() error
MethodB() error
MethodC() error
MethodD() error
MethodE() error
MethodF() error
MethodG() error
MethodH() error
MethodI() error
MethodJ() error
MethodK() error
MethodL() error
}