これは、オブジェクト指向言語の継承の概念と大まかに比較できます。継承のような動作をシミュレートするために使用されることが後でわかります。 Go 言語における継承は埋め込みまたは合成によって実装されるため、Go 言語では継承よりも合成の方が一般的であると言えます。
次のプログラムを考えてみましょう。
package main
import "fmt"
type innerS struct {
in1 int
in2 int
}
type outerS struct {
b int
c float32
int // 無名フィールド
innerS // 無名フィールド
}
func main() {
outer := new(outerS)
outer.b = 6
outer.c = 7.5
outer.int = 60
outer.in1 = 5
outer.in2 = 10
fmt.Printf("outer.b is: %d\n", outer.b)
fmt.Printf("outer.c is: %f\n", outer.c)
fmt.Printf("outer.int is: %d\n", outer.int)
fmt.Printf("outer.in1 is: %d\n", outer.in1)
fmt.Printf("outer.in2 is: %d\n", outer.in2)
// 構造体リテラルを使用する
outer2 := outerS{6, 7.5, 60, innerS{5, 10}}
fmt.Printf("outer2 is:", outer2)
}
実行結果は次のとおりです。
outer.b is: 6
outer.c is: 7.500000
outer.int is: 60
outer.in1 is: 5
outer.in2 is: 10
outer2 is:{6 7.5 60 {5 10}}
匿名フィールドに格納されるデータは、outer.int 型の名前によって取得されるため、構造体の各データ型に対して匿名フィールドは 1 つだけ存在できると結論付けることができます。
埋め込み構造
同様に、構造体もデータ型であるため、上記の例のように匿名フィールドとして使用することもできます。外部構造は、outer.in1 を通じて内部構造のフィールドに直接アクセスし、内部構造は他のパッケージから取得することもできます。内部構造体は、外部構造体に単純に挿入またはインライン化されます。この単純な「継承」メカニズムは、別の型から実装の一部またはすべてを継承する方法を提供します。
サンプルコードは次のとおりです。
package main
import "fmt"
type A struct {
ax、ay int
}
type B struct {
A
bx、by float32
}
func main() {
b := B {A {1,2}, 3.0, 4.0}
fmt.Println(b.ax, b.ay, b.bx, b.by)
fmt.Println(b.A)
}
出力:
1 2 3 4
{1 2}
構造埋め込みプロパティ
Go 言語の構造には次のような機能が組み込まれています。
1) 埋め込み構造体はそのメンバー変数に直接アクセスできます。
埋め込み構造のメンバーには、外部構造のインスタンスを通じて直接アクセスできます。構造体に埋め込み構造体の複数の層がある場合、構造体インスタンスは、埋め込み構造体メンバーの任意のレベルにアクセスするときに、従来の構造体フィールドの最終フィールドのように構造体フィールドの層を介してアクセスするのではなく、フィールド名を指定するだけで済みます。たとえば、ins.abc へのアクセスは ins.c に簡略化できます。
2) 埋め込み構造体のフィールド名はその型名です
埋め込み構造フィールドでは、引き続きレイヤーごとのアクセスに詳細フィールドを使用できます。埋め込み構造のフィールド名はその型名です。コードは次のとおりです:
var c Color
c.BasicColor.R = 1
c.BasicColor.G = 1
c.BasicColor.B = 0
構造体には同じ型のメンバーを 1 つだけ埋め込むことができるため、構造体の名前変更や間違った割り当てを心配する必要はありません。コンパイラは、割り当てのあいまいさの可能性を検出するとエラーを報告します。