🐕

[Go]構造体を学ぶ

2021/11/26に公開

エンジニアの皆様、お疲れ様です。
前回はポインタについてまとめましたが、
https://zenn.dev/marietty/articles/595e9e72cb6cd2

今日は構造体について復習しつつまとめていこうと思います。

■ 構造体とは?

Go言語ではクラスが存在しません。その代わりに似たような機能として構造体を使用します。

type Me struct {
   name   string 
   gender string
   age    int
}

type 構造体名 struct {} で定義することができます。
{}の中にフィールド名と型名を書きます。

構造体のフィールド名の先頭の文字を小文字にすると、importで呼び出した時にアクセスできないpriveteな構造体になります。

type Me struct {
   name, gender string 
   age          int
}

同じ型名を使用する場合は、フィールド名をカンマ区切りにすることでまとめることもできます。

func main() {
  type Me {
    name   string 
    gender string 
    age    int
  }
  m := &Me{"hanako", " woman", 100}
  fmt.Println(m.name, m.gender, m.age) // hanako, woman, 100
}

処理の中に定義することも可能です。

■ 構造体の使い方

構造体を使った実装の仕方をいくつか紹介します。

□ 構造体の初期化方法

type Me struct {
  name   string 
  gender string 
  age    int
}

func main() {
  me := new(Me)  // 初期化する
  me.name = "hanako" // nameに値を代入
  me.gender = "woman" // genderに値を代入
  me.age = 100 // ageに値を代入

  fmt.Println(me) // hanako, woman, 100
}

構造体の初期化を行なってから値を代入しています。

type Me struct {
  name   string 
  gender string 
  age    int
}

func main() {
  me1 :=  &Me{"hanako", "woman", 100}
  fmt.Println(me1) // hanako, woman, 100
  
  me2 := &Me {
    name: "hanako",
    gender: "woman",
    age: 100,
  }
  fmt.Println(me2) // hanako, woman, 100
}

me1は {} の中にフィールド名の定義順に値を渡しています。
me2はフィールド名の後に:をつけて値を渡しています。
どちらの方法でも構造体を使用して値をセットすることができます。
実際の業務では、me2の値の格納方法が一番使われているのではないかと思っています。

□ 構造体内にメソッド/関数を定義

冒頭で書いたように、Go言語には、クラスはありません。
しかし、構造体内にメソッド/関数を定義することができます。
通常のメソッド/関数と違う点はレシーバーを使用する点です。

type Me struct {
  name   string 
  gender string 
  age    int
}

func main(){
  me := Me{"hanako", "woman", 100}
  fmt.Println(me.hogeFunc("Hello!!")) //=> Hello!!私の名前は、hanakoです。
}

func (m Me) hogeFunc(greeting string) string{
    return greeting + "私の名前は、" + m.name + "です。"
}

func の後の (m Me)がレシーバーです。
hogeFuncメソッドはmという名前の、Me型を持っているという意味になります。

初めは混乱してしまいますが、徐々に慣れてきます、、、私は慣れるまで二週間ほどかかりましたorz

また、クラスの継承に似た構造体の埋め込みを行うことも可能です。

type Person struct {
	firstName string
	lastName  string
}

type Me struct {
	Person
}

func (m Me) printName() string {
	return m.firstName + m.lastName
}

func main() {
	p := Me{}
	p.firstName = "田中"
	p.lastName = "花子"
	fmt.Println(p.printName()) // 田中花子
}

同じ構造体を使い回したりすることもできそうですね。

■ 構造体での配列とループ

type Person struct {
   name string
   age  int
}

func main() {
   p := []*Person{
   	{"tarou", 10},
   	{"hanako", 20},
   }

   fmt.Println(*p[0]) // tarou 10
   fmt.Println(*p[1]) // hanako 10
}

配列は、構造体の名前の前に[]をつけることで定義することができます。

type Person struct {
  name string
  age  int
}

func main() {
  p := []*Person{
  	{"tarou", 10},
  	{"hanako", 20},
  }
  
// 配列に新しく追加
p = append(p, &Person{"hoge", 30})

// ループ処理を入れて配列の中身を表示させてみる
  for index, v := range p {
  	fmt.Println(index, ":", v.name, v.age)
  }
}

実行結果

0 : tarou 10
1 : hanako 20
2 : hoge 30

慣れないうちは、
https://go.dev/play/
Playgroundを使用して試してみると勉強になります。

■ まとめ

Go言語では存在しないクラスの代わりに構造体を定義する。
JavaScriptのオブジェクトのような情報を一つにまとめた物です。

typeとstructで定義することができる。

Discussion