構造体の埋め込みについて
例えば人を定義するとき、その構造体の中に「住所」という情報を混ぜることになったとします。このとき、以下のように構造体の中で構造体を利用することになります。これを構造体の埋め込みと言います。
package main
import "fmt"
type Address struct {
Street string
City string
PostalCode int
}
type Person struct {
FirstName string
LastName string
Age int
Address
}
フィールドへのアクセス
このとき、Addressの中のStreetフィールドの値を利用するときは以下のようにアクセスすると思います。
func main() {
p := Person{
FirstName: "John",
LastName: "Doe",
Age: 30,
Address: Address{
Street: "123 Main St",
City: "Anytown",
PostalCode: 12345,
},
}
fmt.Println(p.Address.Street)
}
しかし、Go言語ではこのようにPerson
構造体を宣言すると、インスタンス利用時には埋め込んだAddress
構造体のフィールドがあたかも同階層で宣言されたかのようにアクセスすることが可能になります。
// 以下は同じ結果になる
fmt.Println(p.Address.Street)
// 123 Main St
fmt.Println(p.Street)
// 123 Main St
これはプロパティだけではなく、メソッドでも同じようにアクセスすることが可能になります。
Address
構造体にGetAddress()
をメソッドとして定義します。
この場合も同様に同階層にあるようにアクセスすることが可能になります。
func (a Address) GetAddress() string {
return fmt.Sprintf("%s, %s, %d", a.Street, a.City, a.PostalCode)
}
func main() {
p := Person{...
// 以下2つは同じ結果
fmt.Println(p.Address.GetAddress())
fmt.Println(p.GetAddress())
}
複数の埋め込みと同名のフィールドがある場合
同名のフィールドがある場合は上記のようにアクセスすることはできなくなりエラーになります。
以下の場合コンパイルエラーになります。
type Address struct {
Street string
City string
PostalCode int
}
type Person struct {
FirstName string
LastName string
Age int
Address
ContactInfo
}
type ContactInfo struct {
Email string
PhoneNumber string
City string
}
func main() {
p := Person{...
// Error : ambiguous selector p.City compiler(AmbiguousSelector)
fmt.Println(p.City)
}
そのため上記のような場合はフィールド・メソッドともにどの構造体のフィールドにアクセスするのかを明示する必要が発生します
fmt.Println(p.Address.City)
fmt.Println(p.ContactInfo.City)
個人的には同階層として扱える状況でもどの構造体のフィールドにアクセスしているのか明示するほうが可読性が向上すると思いました