モジュールのレッスン (3/5)
合成(埋め込み)
Go には 継承はありません。再利用に対する慣用的な答えは次のとおりです。 構成、特に埋め込み: 1 つのタイプを含む フィールド名を指定せずに別の内部に追加します。フィールドとメソッド 埋め込み型は昇格され、あたかも直接アクセス可能になります。 彼らは外側のタイプに属していました。
構造体の埋め込み
type Animal struct {
Name string
}
func (a Animal) Greet() string {
return "ciao da " + a.Name
}
type Dog struct {
Animal // embedding — NO field name
Breed string
}
c := Dog{
Animal: Animal{Name: "Rex"},
Breed: "Pastore",
}
fmt.Println(c.Name) // "Rex" — promoted from Animal
fmt.Println(c.Greet()) // "ciao da Rex" — promoted method
fmt.Println(c.Breed) // own field埋め込みフィールドには 型の名前によって引き続きアクセスできます:
c.Animal.Name は機能し、c.Name と同じです。こんなときに必要になります
衝突があります。
オーバーライド (部分的): メソッド「シャドウイング」
外部型がプロモートされた型と同じ名前のメソッドを定義している場合 1 つは、その方法が「勝つ」ということです。内部からいつでも組み込みにアクセスできます 1 つはタイプの名前によるものです。
func (c Dog) Greet() string {
return "BAU! " + c.Animal.Greet()
}これはポリモーフィックな継承ではなく、単なる字句上の名前解決です。 ポリモーフィズムには インターフェイス (モジュール 6) を使用します。
複数の埋め込み
複数のタイプを埋め込むことができます。
type Logger struct{ /*...*/ }
func (l Logger) Log(msg string) { /*...*/ }
type Timer struct{ /*...*/ }
func (t Timer) Now() time.Time { /*...*/ }
type Service struct {
Logger
Timer
Name string
}
s := Service{Name: "api"}
s.Log("start") // promoted from Logger
s.Now() // promoted from Timer2 つの埋め込み型に同じ名前のメソッドがある場合、直接アクセス
曖昧になり、コンパイラは明示的な形式を必要とします
(s.Logger.Foo() または s.Timer.Foo())。
インターフェースの埋め込み
インターフェイスを「埋め込む」こともできます (モジュール 6 を参照)。
type ReadWriter interface {
io.Reader
io.Writer
}これは、Reader と Writer のメソッドの結合と同等です。
明示的な合成 (埋め込みではない) を使用する場合
名前付きフィールドが必要で自動昇格が必要ない場合は、プレーンを使用します 構成:
type Dog struct {
Anim Animal // NORMAL field, no promotion
Breed string
}
c.Anim.Name // you need the field name埋め込みは便利な 委任ツール であり、設計上の選択ではありません 明示的な合成よりも厳密に優れています。本当に必要な場合に使用してください。 内部型の API を促進します。
試してみてください
Animal (埋め込み、フィールド名なし) を埋め込み、品種文字列フィールドを持つ Dog を定義します。
ヒントを表示
埋め込み: フィールド名を指定せずに TYPE を記述します。
3 回の試行後に解決策が利用可能になります
Greet() 文字列メソッドを Animal に追加し、Dog 変数で直接呼び出します (メソッドのプロモーション)。
ヒントを表示
Animal で定義されたメソッドは、埋め込みのおかげで Dog に昇格されます。
3 回の試行後に解決策が利用可能になります
Go は古典的な継承をサポートしていますか?
type B struct { /* extends A? */ }要約
- 継承なし: 埋め込みを使用して作成します。
- 埋め込み = 構造体にフィールド名を付けずに TYPE を書き込むこと。
- 埋め込み型のフィールドとメソッドは 昇格されます。
- 明示的なアクセスは常に利用可能です:
outer.Inner.Field。 - 「字句」オーバーライド: 外側の型のメソッドは、プロモートされた型のメソッドをシャドウします。
- 埋め込み ≠ is-a: ポリモーフィズムには インターフェイス を使用します。