Go 言語仕様9（構造体）

## 概要
Go 言語の仕様まとめ。

前回：
[Go 言語仕様8（ポインタ）](https://qiita.com/R_R/items/576fa6ee9da4991c4336)

## 内容

- 構造体
  - 宣言・代入
  - ポインタ
  - メソッド
  - 多重構造体
  - スライスとの合せ技

## 構造体

- **宣言方法**

構造体では、複数の任意の型を一つにまとめることができる。

```Go:宣言・代入
// 複数の任意の型を一つにまとめることができる
type Structure struct {
	// 外部パッケージがら呼び出せるように、先頭一文字は大文字にしておく
	Amount   int
	Language string
	Decimal  float64
	Bl       bool
}

func main() {
	// 変数の宣言方法と同じ
	var st Structure
	st2 := Structure{}
	// 各型の初期値が出力されることを確認
	fmt.Println(st) // {0  0 false}
	fmt.Println(st2) // {0  0 false}

	// 値を代入（.で各フィールドにアクセスできる）
	st.Amount = 1000
	st.Language = "Golang"
	fmt.Println(st.Amount, st.Language) // 1000 Golang

	// 初期値を指定して宣言
	st3 := Structure{
		Amount:   2000,
		Language: "Java",
		Decimal:  1.234,
		Bl:       true,
	}
	fmt.Println(st3) // {2000 Java 1.234 true}

	// 構造体のフィールドの順番で値のみを入れることも可能
	st4 := Structure{3000, "Python", 3.14, false}
	fmt.Println(st4)

	// 全フィールド分代入する必要がある
	st5 := Structure{3000, "Python", 3.14} // too few values in struct literal
}
```
　　

- **ポインタ**

構造体は値型のため、関数へ引数で渡したときなどは、元の構造体の値に影響がない。

```Go:値渡し
type Structure struct {
	Amount   int
	Language string
}

func Modify(st Structure) {
	st.Amount = 9999
	st.Language = "Golang"
}

func main() {
	var st Structure
	Modify(st)
	fmt.Println(st) // {0 }
}
```
そのため、ポインタ変数を作り、関数へ参照渡しする。

```Go:参照渡し
type Structure struct {
	Amount   int
	Language string
}

func Modify(st Structure) {
	st.Amount = 9999
	st.Language = "Golang"
}

func Modify2(st *Structure) {
	st.Amount = 9999
	st.Language = "Golang"
}

func main() {
	var st Structure
	Modify(st)
	fmt.Println(st)

	// 構造体のポインタを明示的に作る方法が推奨パターン
	st2 := &Structure{}
	Modify2(st2)
	fmt.Println(*st2) // {9999 Golang}

	// 非推奨パターンA
	st3 := Structure{}
	Modify2(&st3)

	// 非推奨パターンB
	st4 := new(Structure)
	Modify2(st4)
}
```
　　

- **メソッド**

　メソッド：
　　構造体に紐付く処理群。紐付けた構造体でのみ使用可能。

　関数：
　　構造体に紐付かない処理群。

　レシーバ：
　　メソッドと紐付いた構造体。

```Go:関数を使った構造体の値更新
type Structure struct {
	Amount   int
	Language string
}

func Modify(st *Structure) {
	st.Amount = 2000
}

func main() {
	// 関数を使った構造体の値更新
	st := &Structure{100, "Golang"}
	Modify(st)
	fmt.Println(st) // &{2000 Golang}
}
```

```Go:メソッドを使った構造体の値更新
type Structure struct {
	Amount   int
	Language string
}

// メソッドのレシーバーはポインタ型にするのが一般的
func (st *Structure) Modify() {
	// レシーバーの値を書き換える
	st.Amount = 3000
}

func main() {
	st := &Structure{100, "Golang"}

	// レシーバー.メソッドで呼び出し
	st.Modify()
	fmt.Println(st) // &{３000 Golang}
}
```
　　

- **多重構造体**

親子関係のような感じで、構造体を構造体のフィールドとして定義できる。

```Go:多重構造体
type SubStructure1 struct {
	Amount   int
	Language string
}

type SubStructure2 struct {
	Decimal float64
	Bl      bool
}

// 構造体をフィールドで持てる
type Structure struct {
	SubStructure1 SubStructure1
	// フィールド名が同じであれば、型宣言は省略可能
	SubStructure2
}

// メソッド
func (subst *SubStructure1) Modify() {
	subst.Amount = 9000
	subst.Language = "Java"
}

func main() {
	// 子の構造体にアクセスできる
	st2 := Structure{}
	fmt.Println(st2) // {{0 } {0 false}}

	// 値を入れる
	st2.SubStructure1.Amount = 100
	st2.SubStructure1.Language = "Golang"
	// 型宣言を省略した場合は、子の構造体に直接アクセス可能
	st2.Decimal = 1.234
	st2.Bl = true
	fmt.Println(st2) // {{100 Golang} {1.234 true}}

	// 値を入れつつ宣言
	st3 := Structure{
		SubStructure1: SubStructure1{
			Amount:   8000,
			Language: "Golang",
		},
	}
	fmt.Println(st3) // {{8000 Golang} {0 false}}

	// 親の構造体からこの構造体のメソッドを呼び出せる
	st2.SubStructure1.Modify()
	fmt.Println(st2)
}
```
　　

- **スライスとの合せ技**

構造体をスライスで扱える。

```Go
type Structure struct {
	Amount   int
	Language string
}

// 子の構造体をスライスでフィールドに持つ構造体
type SliceStruct struct {
	Structure []*Structure
}

func main() {
	// スライスで構造体を定義できる
	sl := make([]Structure, 3)
	fmt.Println(sl) // [{0 } {0 } {0 }]

	// 各スライスに値を代入
	sl[0].Amount = 100
	sl[1].Language = "Golang"
	sl[2].Amount = 200
	fmt.Println(sl) // [{100 } {0 Golang} {200 }]

	// スライスの構造体を定義して、
	v := Structure{100, "Galang"}
	v2 := Structure{100, "Java"}
	v3 := Structure{100, "Python"}
	// appendする
	slst := SliceStruct{}
	slst.Structure = append(slst.Structure, &v, &v2, &v3)
	// forで値を取り出す
	for _, v := range slst.Structure {
		fmt.Println(v)
	}
}
```

## 次回

[Go 言語仕様10（テスト）](https://qiita.com/R_R/items/d0cc8ba4eac5726c7b83)