Go 言語には継承の仕組みはありませんが、埋め込み (Embedding) という仕組みによって型の拡張(結合)を行うことができます。
インタフェース埋め込み (Interface Embedding)
Go 言語標準の io
パッケージには、下記のような Reader
インタフェースと Writer
インタフェースが定義されています。
type Reader interface {
Read(p []byte) (n int, err error)
}
type Writer interface {
Write(p []byte) (n int, err error)
}
ここで、Read
メソッドと Write
メソッドを両方とも備えるインタフェースを単純に定義しようとすると、下記のように記述することになります。
type ReadWriter interface {
Read(p []byte) (n int, err error)
Write(p []byte) (n int, err error)
}
Go 言語では、このようなケースのために 埋め込み (Embedding) の仕組みが提供されており、次のように既存のインタフェースを再利用する形で新しいインタフェースを定義することができます。
type ReadWriter interface {
Reader
Writer
}
ReadWriter
インタフェースを備えるオブジェクトは、ReadWriter
型のパラメータを取る関数だけでなく、Reader
型のパラメータを取る関数や、Writer
型のパラメータを取る関数にも渡すことができます。
ちなみに、この ReadWriter
インタフェースも標準の io
パッケージで定義されています。
構造体埋め込み (Struct Embedding)
埋め込み (Embedding) の仕組みは、インタフェースだけでなく、構造体でも同様に使用することができます。
下記の例では、Product
構造体を埋め込む形で Stock
構造体を定義しています。
Product
構造体は、メソッドを1つ実装しています。
type Product struct {
Model string
Name string
Price int
}
func (p *Product) AdLabel() string {
return fmt.Sprintf("%s (%s)", p.Model, p.Name)
}
type Stock struct {
*Product
Quantity int
}
Product
構造体に定義されているフィールドやメソッドは、Stock
オブジェクト経由で直接参照することができます。
Stock
オブジェクトは下記のように生成します。
s := &Stock{
Product: &Product{Model: "PR102", Name: "Printer", Price: 300},
Quantity: 100,
}
fmt.Println(s.Model) //=> PR102
fmt.Println(s.AdLabel()) //=> Printer (PR102)
オブジェクト生成時は、埋め込んだ構造体のオブジェクトを生成して初期化しなければいけないことに注意してください(初期化すべきフィールドの名前も、埋め込んだ構造体の型名と同じになります)。 次のように、埋め込んだ構造体のフィールドを直接初期化することはできません。