0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

[Go言語] 初心者必見シリーズ: 構造体(Structs)

Posted at

構造体

構造体は、フィールド(field)の集まりです。

定義方法

構造体は下記のように typestruct を使用して定義します。

  • 構文

    type 構造体の名前 struct {
        フィールド名 型名
        フィールド名 型名
        フィールド名 型名
        ...
    }
    

    同じ型のフィールド名は、カンマ区切りで書くことができます。

    type 構造体の名前 struct {
        フィールド名, フィールド名, フィールド名 型名
        フィールド名 型名
    }
    
  • 人のデータをまとめた構造体です。

      type People struct {
              Name string
              Sex string
              Age int
              Height int
              Weight int
      }
    

初期化

方法1:Key:Valueで初期化します。

people := People{Name: "太郎"}

設定しない要素は ゼロ値 で初期化される。

方法2:要素の定義順に初期化します。

people := People{"太郎", "男", ...}

この方法では、全部のfieldを設定する必要があります。

方法3:定義後にドット(.)を用いてfieldを初期化します。

people := People{}
people.Sex = "男"
people3.Age = 8

構造体へのポインター(Pointer to structs)

方法1:& (アドレス演算子)で構造体へのPointerを取得します。

people := People{Name: "太郎"}
p := &people
(*p).Name = "花子"

(*p)p に省略できます。

p.Name = "花子"

方法2: new(構造体名) で構造体へのポインターを生成します。

people := new(People) // Peopleのポインタ型
(*people).Name = "花子"
people.Name = "花子"  // (*people) は peopleに省略できます。

new(T) はT型の無名変数(unnamed variable)を作成し、それを T のゼロ値へ初期化し、 *T 型の値であるそのアドレスを返します。

new(People)&People{} は等価です。

タグ(Tag)

Go構造体タグは、Go構造体宣言のフィールドの後に表示される注釈です。

実行時にreflectパッケージでその情報を取得し利用したりします。

良くある構造体をJSONに変換する例として、

下記のようにフィールドの後ろに json タグをつけると、

  type People struct {
          Name string		`json:"name"`
          Sex string		`json:"sex"`
          Age int				`json:"age"`
          Height int		`json:"height"`
          Weight int		`json:"weight"`
  }

Go言語の json 標準パッケージで構造体をJSONに変換すると、フィールド名がTagで定義された名前に置換されます。

people := People{Name: "太郎", Sex: "男"}
jsonBytes, _ := json.Marshal(people)
fmt.Println(string(jsonBytes)) 
// JSON: {"name": "太郎", "sex": "男"}

その仕組み

jsonパッケージの内部で下記のようにタグ情報を取得してJSONデータに変換しています。

 t := reflect.TypeOf(people)
 for i := 0; i < t.NumField(); i++ {
     field := t.Field(i)
     tag := field.Tag.Get("json") //  `json`タグ情報を取得
 }

下記のように、複数のタグはスペースで区切って記述できます。

  type People struct {
          Name string		`json:"name" validate:"required"`
          Sex string		`json:"sex" validate:"required"`
          Age int				`json:"age" validate:"required"`
          Height int		`json:"height" validate:"required"`
          Weight int		`json:"weight" validate:"required"`
  }

埋め込みフィールド(Embedded fields)

型だけで宣言されていて、明示的なフィールド名がないフィールドを埋め込みフィールドと呼びます。

image-20200801172005624.png

Go言語は埋め込みで他言語のクラスの継承ぽいことができます。

埋め込み子構造体(Address)のフィールドが昇格し、構造体の外(Person)からダイレクトにアクセスすることが可能です。

person.Adress.city  person.city
person.Adress.state  person.state
// PersonがAdressを継承しているように、Adressのフィールドをダイレクトにアクセスすることが可能となります。

Person に同名のフィールドやメソッドがあるときは、Address にあるそのフィールドは昇格されないです。

image-20200801173432397.png

構造体の比較

reflect.DeepEqual はポインターか否かにかかわらず、

フィールドの値が同じであれば true を返します。

import (
    "reflect"
)

...
people1 := People{Name: "太郎"}
people2 := People{Name: "太郎"}

println(reflect.DeepEqual(people1, people2))     // true
println(reflect.DeepEqual(&people1, &people2))   // true
println(people1 == people2)    // true
println(&people1 == &people2)  // false

動画(YouTube)

元記事

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?