Go言語の構造体
2026/09/13
構造体型
構造体は、名前と型を持つフィールドを並べた型です。フィールドは宣言した順に並び、名前は重複できません。同じ型のフィールドはX, Y float64のように1行にまとめられます。フィールド名も識別子なので、先頭が大文字なら他パッケージから参照できます。フィールドにアクセスするときは、値.フィールド名の形式で書きます。
構造体型の変数を定義して何も代入しない場合、各フィールドはゼロ値で埋まります。
type Point struct {
X, Y float64
}
var p Point
p.X = 1
fmt.Println(p.X) // 1_はブランク識別子で、フィールド名にも使えますが、名前として参照できないためp._とは書けません。同じ構造体に何度でも書くことができ、領域だけ確保するパディングの用途で使用できます。
type Header struct {
Flag uint8
_ [3]byte
Size uint32
}構造体リテラル
フィールドをまとめて初期化するときは構造体リテラルを使います。
p1 := Point{1, 2} // Pointの値
p2 := Point{X: 1, Y: 2} // Pointの値
p3 := &Point{X: 1, Y: 2} // *Point
// p3と同じ意味
p := Point{X: 1, Y: 2}
p4 := &p // *Pointp1とp2は構造体型の値です。p3は構造体リテラルのアドレスをその場で取った*Pointです。pを用意してp4 := &pとする書き方も同じ意味で、p3とp4は同じ型・同じ内容のポインタになります。
*Pointを引数に取る関数へ渡すときや、構造体のフィールドがポインタ型のときに&T{...}がよく使われます。ゼロ値へのポインタだけ欲しいときはnew(Point)も使えますが、フィールドを初期値で埋めたいときは&Point{X: 1, Y: 2}の方が意図が読み取りやすいです。
埋め込みによる合成
フィールドに別の型名を書くと埋め込みになります。埋め込みは継承ではなく合成です。埋め込まれたフィールドやメソッドは外側に昇格し、c.Powerのように直接アクセスできます。
type Engine struct{ Power int }
type Car struct {
Engine
Model string
}
c := Car{Engine: Engine{Power: 150}, Model: "compact"}
fmt.Println(c.Power) // 昇格比較
すべてのフィールドの型が比較可能なときだけ==と!=が使えます。スライス、マップ、関数を含む構造体は比較できません。等価なのは、型が同じで、対応する_以外のフィールドがすべて等しいときです。
a := Point{X: 1, Y: 2}
b := Point{X: 1, Y: 2}
fmt.Println(a == b) // true
c := Point{X: 1, Y: 3}
fmt.Println(a == c) // false
type Vertex struct {
X, Y float64
}
// fmt.Println(a == Vertex{X: 1, Y: 2}) // コンパイルエラー: 型が違う
fmt.Println(a == Point(Vertex{X: 1, Y: 2})) // true
type Record struct {
Tags []string
}
var r1, r2 Record
// fmt.Println(r1 == r2) // コンパイルエラー: 比較できないフィールドがある