Go/struct
Goにおけるstruct
キーワードは、複数のフィールドをまとめた複合データ型を定義するために使用されます。
1. structの基本概念
structは異なる型のデータを1つの論理的な単位にグループ化するための仕組みです。オブジェクト指向言語のクラスに似ていますが、継承の概念はありません。
2. structの宣言と定義
2.1 基本的な定義
type Person struct { FirstName string LastName string Age int }
2.2 タグ付きフィールド
type User struct { ID int `json:"id" db:"user_id"` Username string `json:"username" db:"username"` Email string `json:"email,omitempty" db:"email"` }
2.3 埋め込みフィールド
type Address struct { Street string City string Country string } type Employee struct { Name string Address // 埋め込みフィールド }
2.4 無名struct
var point struct { X int Y int }
3. structの初期化
3.1 フィールド名指定による初期化
p := Person{ FirstName: "John", LastName: "Doe", Age: 30, }
3.2 順序による初期化(非推奨)
p := Person{"John", "Doe", 30}
3.3 newによる初期化
p := new(Person) // すべてのフィールドがゼロ値で初期化される
3.4 無名structの初期化
point := struct { X int Y int }{ X: 10, Y: 20, }
4. structの操作
4.1 フィールドへのアクセス
p := Person{FirstName: "John", LastName: "Doe", Age: 30} fmt.Println(p.FirstName) // "John" p.Age = 31 // フィールドの更新
4.2 埋め込みフィールドへのアクセス
e := Employee{ Name: "John", Address: Address{ Street: "123 Main St", City: "Boston", Country: "USA", }, } fmt.Println(e.Street) // フィールド昇格: e.Address.Streetと同じ
4.3 ポインタを通したフィールドアクセス
p := &Person{FirstName: "John", LastName: "Doe", Age: 30} fmt.Println(p.FirstName) // (*p).FirstNameと同じ
5. structメソッドの定義
5.1 値レシーバによるメソッド
func (p Person) FullName() string { return p.FirstName + " " + p.LastName } // 使用例 p := Person{FirstName: "John", LastName: "Doe"} fmt.Println(p.FullName()) // "John Doe"
5.2 ポインタレシーバによるメソッド
func (p *Person) SetAge(age int) { p.Age = age } // 使用例 p := Person{Age: 30} p.SetAge(31) // (&p).SetAge(31)と同じ fmt.Println(p.Age) // 31
6. structの特殊な使い方
6.1 空struct
type Void struct{} void := struct{}{} // メモリを消費しない空構造体 // setとしての利用 set := make(map[string]struct{}) set["apple"] = struct{}{}
6.2 匿名struct
data := []struct { Name string Age int }{ {"John", 30}, {"Jane", 25}, }
6.3 structのコピー
p1 := Person{FirstName: "John", LastName: "Doe", Age: 30} p2 := p1 // p1のすべてのフィールドがp2にコピーされる
6.4 structを含む型定義
type PersonMap map[string]Person type PersonList []Person type IntPair struct{ First, Second int }
7. インターフェースとの関係
7.1 インターフェースの実装
type Stringer interface { String() string } func (p Person) String() string { return fmt.Sprintf("%s %s (%d)", p.FirstName, p.LastName, p.Age) } // Personは暗黙的にStringerインターフェースを実装 var s Stringer = Person{"John", "Doe", 30}
8. 構造体の比較
8.1 等値比較
p1 := Person{FirstName: "John", LastName: "Doe", Age: 30} p2 := Person{FirstName: "John", LastName: "Doe", Age: 30} fmt.Println(p1 == p2) // true(すべてのフィールドが同じ値)
8.2 比較不能なフィールドを含む構造体
type Data struct { Values []int // スライスは比較不能 } d1 := Data{Values: []int{1, 2, 3}} d2 := Data{Values: []int{1, 2, 3}} // fmt.Println(d1 == d2) // コンパイルエラー
9. JSONとの相互変換
9.1 structからJSONへのエンコード
type Product struct { ID int `json:"id"` Name string `json:"name"` Price int `json:"price,omitempty"` } p := Product{ID: 1, Name: "Apple"} jsonData, err := json.Marshal(p) // {"id":1,"name":"Apple"}
9.2 JSONからstructへのデコード
jsonStr := `{"id":2,"name":"Banana","price":200}` var p Product err := json.Unmarshal([]byte(jsonStr), &p)
10. リフレクション操作
10.1 structのリフレクション
p := Person{FirstName: "John", LastName: "Doe", Age: 30} t := reflect.TypeOf(p) v := reflect.ValueOf(p) for i := 0; i < t.NumField(); i++ { field := t.Field(i) value := v.Field(i) fmt.Printf("%s: %v\n", field.Name, value.Interface()) }
10.2 タグへのアクセス
type Tagged struct { Field1 string `json:"f1" validate:"required"` Field2 int `json:"f2,omitempty"` } t := reflect.TypeOf(Tagged{}) field := t.Field(0) fmt.Println(field.Tag.Get("json")) // "f1" fmt.Println(field.Tag.Get("validate")) // "required"
11. 並行処理での構造体使用
11.1 ミューテックスを埋め込んだ構造体
type SafeCounter struct { sync.Mutex count int } func (c *SafeCounter) Increment() { c.Lock() defer c.Unlock() c.count++ }
以上がGoのstruct
キーワードの主な用途と使い方です。構造体はGoプログラミングの基本的な構成要素であり、データの論理的なグループ化、メソッドの関連付け、interface
の実装など多くの場面で活用されます。