構造体の埋め込みの基本
CoddyのGOジャーニー「オブジェクト指向プログラミング」セクションの一部。レッスン 35/107。
Struct embeddingは、ある struct 型の中に別の struct 型を含めるための Go の仕組みです。field 名を使用する代わりに、型を指定するだけで、Go は埋め込まれた struct の fields を外側の struct に昇格させます。
基本的な構文は次のとおりです。
type Address struct {
City string
Country string
}
type Person struct {
Name string
Address // 埋め込み - フィールド名なし
}
AddressをPersonに埋め込むと、外側の構造体上で埋め込まれたフィールドに直接アクセスできます。
func main() {
p := Person{
Name: "Alice",
Address: Address{
City: "London",
Country: "UK",
},
}
fmt.Println(p.City) // London - 直接アクセス
fmt.Println(p.Country) // UK - 直接アクセス
fmt.Println(p.Address.City) // これも動作する
}
p.Cityが、p.Address.Cityと明示的に記述しなくても機能することに注目してください。Goは埋め込まれた構造体のfieldsを自動的に昇格させ、外側の構造体に属しているかのようにアクセス可能にします。必要に応じて、埋め込み型の名前を通じて引き続きアクセスできます。
これは、内部の field にアクセスするために常に field name を使用する必要がある通常のネストされた構造体とは異なります。Embedding によって、関連するデータの論理的なグループ化を維持しながら、よりフラットで便利な API が作成されます。
チャレンジ
簡単struct embedding を使用して、クリーンで整理されたデータモデルを作成する車両登録システムを構築しましょう。embedding によってすべての fields に直接 access できるようにしながら、contact information と vehicle details を分離します。
コードを2つのファイルに整理します。
vehicle.go: embedding を通じて連携する2つの struct を作成します。ContactInfostruct:OwnerNameとPhoneの fields(どちらも string)を持ちますVehiclestruct:ContactInfoを field name なしで embeds し、独自のMake、Model、Yearfields を追加します
VehicleのSummaryという method も作成します。main.go: input から vehicle と owner の details を読み取り、embeddedContactInfoを持つVehicleinstance を作成し、embedded fields に直接、または embedded type name を通じて access する方法を示します。最後に vehicle summary を出力します。
次の input が提供されます。
- Line 1: Owner name
- Line 2: Phone number
- Line 3: Vehicle make
- Line 4: Vehicle model
- Line 5: Year(integer)
Summary method は、次の Format の string を返す必要があります。
[Year] [Make] [Model] - Owner: [OwnerName], Phone: [Phone]main file では、次の内容を出力して field promotion を示します。
- Vehicle 上で直接 access した owner name(例:
v.OwnerName) - embedded type を通じて access した phone(例:
v.ContactInfo.Phone) Summarymethod による full summary
たとえば、Alice Smith、555-1234、Toyota、Camry、2023 が与えられた場合、出力は次のようになります。
Alice Smith
555-1234
2023 Toyota Camry - Owner: Alice Smith, Phone: 555-1234field promotion による直接 access と、embedded type name を通じた明示的な access の両方の access パターンが機能するため、embedded data を扱う方法に柔軟性が得られることに注目してください。
自分で試してみよう
package main
import (
"bufio"
"fmt"
"os"
"strconv"
"strings"
)
func main() {
reader := bufio.NewReader(os.Stdin)
// 所有者名を読み取る
ownerName, _ := reader.ReadString('\n')
ownerName = strings.TrimSpace(ownerName)
// 電話番号を読み取る
phone, _ := reader.ReadString('\n')
phone = strings.TrimSpace(phone)
// 車両のメーカーを読み取る
make, _ := reader.ReadString('\n')
make = strings.TrimSpace(make)
// 車両のモデルを読み取る
model, _ := reader.ReadString('\n')
model = strings.TrimSpace(model)
// 年を読み取る
yearStr, _ := reader.ReadString('\n')
yearStr = strings.TrimSpace(yearStr)
year, _ := strconv.Atoi(yearStr)
// TODO: 埋め込みの ContactInfo を持つ Vehicle インスタンスを作成する
// 上記の入力から読み取った値を使用する
// TODO: Vehicle 上で直接アクセスした所有者名を出力する(フィールドの昇格)
// 例: fmt.Println(v.OwnerName)
// TODO: 埋め込み型名を通じてアクセスした電話番号を出力する
// 例: fmt.Println(v.ContactInfo.Phone)
// TODO: Summary メソッドを使用して完全なサマリーを出力する
// 例: fmt.Println(v.Summary())
// 解答を実装したら、これらの行を削除してください
_ = ownerName
_ = phone
_ = make
_ = model
_ = year
}
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
オブジェクト指向プログラミングのすべてのレッスン
1Go オブジェクト指向の基礎
外部ファイルGo ワークスペースとモジュールパッケージとインポート公開された名前と非公開の名前Go におけるオブジェクト指向入門クラスとしての構造体構造体へのメソッド定義ポインタレシーバと値レシーバ構造体の初期化コンストラクタ関数まとめ:簡易計算機8エラー処理とOOP
error インターフェースカスタムエラー型エラーラッピング (fmt.Errorf)センチネルエラーerrors.Is() と errors.As()Panic、Defer、Recover復習 - ファイルパーサー自分で練習してみよう: Goオンラインコンパイラ