
Go言語で構造体の中に構造体を埋め込むことができるって本当ですか?
今回は、Go言語の構造体の機能で「構造体に構造体を埋め込む」という、ちょっとややこしい文章で申し訳ないのですが…でも、こういう機能なのです。
他のプログラミング言語では「継承」に近い機能と言えるでしょう。
では、プログラムで確認しながら「構造体に構造体を埋め込む」動きを理解していきましょう。
この記事では、構造体の基本的なことには触れていません。
当ブログ記事を参考にしてみてください。
Go言語の構造体を埋め込むとは?
オブジェクト指向プログラミングの三大要素のひとつである「継承」ですが、Go言語では継承の機能がありません。
ですが、継承に近い機能として「構造体に構造体を埋め込む」ことができます。
構造体を埋め込む定義
「構造体に構造体を埋め込む」には下記のように定義します。
// 構造体に構造体を埋め込む定義
package main
// 埋め込む構造体
type 構造体の型名 struct {
フィールド名1 型
フィールド名2 型
・
・
・
フィールド名x 型
}
// 構造体を埋め込む(標準的な方法)
type 構造体の型名 struct {
構造体のフィールド名 構造体の型
フィールド名1 型
フィールド名2 型
・
・
・
フィールド名x 型
}
// 埋め込んだ構造体の型は省略できる
type 構造体の型名 struct {
構造体のフィールド名
フィールド名1 型
フィールド名2 型
・
・
・
フィールド名x 型
}
func main() {
}
構造体を埋め込む標準的な定義をプログラムで確認
それでは、先程紹介した記述方法で、実際にプログラムを確認していきましょう。

今回はロールプレイングゲームのモンスターを設定してみます。
// 構造体を埋め込む標準的な定義
package main
import "fmt"
type Monster struct {
Name string
Attribute string
}
// 構造体を埋め込む
type MonsterData struct {
Monster Monster
Hp int
Mp int
attack int
defense int
}
func main() {
// 構造体を初期化
slimeData := MonsterData{
Monster: Monster{
Name: "スライム",
Attribute: "スライム属",
},
Hp: 80,
Mp: 0,
attack: 10,
defense: 10,
}
// slimeDataを出力
fmt.Println(slimeData)
// 埋め込んだ構造体(MonsterData)の値を取り出す
fmt.Println(slimeData.Monster)
// Nameの値を取り出す
fmt.Println(slimeData.Monster.Name)
}
// 出力結果
$ go run main.go
{{スライム スライム属} 80 0 10 10}
{スライム スライム属}
スライム
{{スライム スライム属} 80 0 10 10}
構造体の出力結果を見てみると、構造体の中に {}
で囲まれている部分が埋め込んだ構造体のデータになります。
値の取り出しには . を使って、目的の値まで掘り下げていくイメージになります。
型を省略して構造体を埋め込む定義をプログラムで確認
構造体を埋め込む時に、型を省略することができます。
型を省略して構造体を埋め込む定義をプログラムで確認で実際に確認してみましょう。
// 構造体を埋め込む標準的な定義
package main
import "fmt"
type Monster struct {
Name string
Attribute string
}
// 埋め込んだ構造体の型は省略できる
type MonsterData struct {
Monster // 型を省略している
Hp int
Mp int
attack int
defense int
}
func main() {
// Monsterを初期化
metalslime := Monster{
Name: "メタルスライム",
Attribute: "メタルスライム属",
}
// 変数metalslimeを構造体に埋め込んで初期化
metalslimeData := MonsterData{
Monster: metalslime,
Hp: 10000,
Mp: 300,
attack: 100,
defense: 20000,
}
fmt.Println(metalslimeData)
// metalslimeDataの名前を取り出す
fmt.Println(metalslimeData.Monster.Name)
// 埋め込んだ構造体の型を省略した場合のみ型を省略できる
fmt.Println(metalslimeData.Name)
}
// 出力結果
$ go run main.go
{{メタルスライム メタルスライム属} 10000 300 100 20000}
メタルスライム
メタルスライム
今回は埋め込む先の構造体 Monster
を先に初期化して埋め込んでいます。

コード少し見やすくなりますね!
今回は構造体を埋め込む時に型を省略していますが、値を取り出すところで気になるところがありませんか?

あれ?fmt.Println(metalslimeData.Name)
で型が省略されてますね。
ここに違いがあり、これは型を省略して構造体を埋め込んだ時のみ使用できます。
もし、型を省略せずに fmt.Println(metalslimeData.Name)
のように値を取得しようとすると…
// 出力結果
$ go run main.go
# command-line-arguments
./main.go:63:28: metalslimeData.Name undefined (type MonsterData has no field or method Name)
「 metalslimeData.Name が未定義です」「タイプ MonsterData にはフィールドまたはメソッド名がありません」というエラーが出力されます。
【まとめ】Go言語で構造体を埋め込むには
今回は構造体を埋め込む機能と値の取り出しについて紹介してきました。
それでは、まとめにはいります。
構造体を埋め込む定義方法
構造体に構造体を埋め込むには2種類の方法がありました。
// 構造体に構造体を埋め込む定義
package main
// 埋め込む構造体
type 構造体の型名 struct {
フィールド名1 型
フィールド名2 型
・
・
・
フィールド名x 型
}
// 1.構造体を埋め込む(標準的な方法)
type 構造体の型名 struct {
構造体のフィールド名 構造体の型
フィールド名1 型
フィールド名2 型
・
・
・
フィールド名x 型
}
// 2.埋め込んだ構造体の型は省略できる
type 構造体の型名 struct {
構造体のフィールド名
フィールド名1 型
フィールド名2 型
・
・
・
フィールド名x 型
}
以上です。
今回のプログラムは機能を理解するために単純なプログラムでしたが、構造体の埋め込みは活用することが多い機能です。
実際にいろんなパターンで、あなたがコードを書いて動きを確かめてみましょう。
comment