コンテンツにスキップ

Go/構造体

出典: フリー教科書『ウィキブックス(Wikibooks)』
< Go


構造体

[編集]

構造体は、フィールドと呼ばれる名前の付いた要素の集まりで、それぞれのフィールドは名前と型を持っています。 フィールド名は、明示的に(IdentifierList)または暗黙的に(EmbeddedField)指定できます。 構造体の中では、空白でないフィールド名は一意でなければなりません[1]

構造体の例
package main

import "fmt"

func main() {
	item := struct {
		Name  string
		Price int
	}{
		Name:  "牛乳",
		Price: 150,
	}

	fmt.Println("品名は ", item.Name)
	fmt.Println("単価は ", item.Price)
	fmt.Println(item)
	fmt.Printf("%%v: %v\n", item)
	fmt.Printf("%%+v: %+v\n", item)
	fmt.Printf("%%#v: %#v\n", item)
}
実行結果
品名は 牛乳
単価は 150
{牛乳 150}
%v: {牛乳 150}
%+v: {Name:牛乳 Price:150}
%#v: struct { Name string; Price int }{Name:"牛乳", Price:150}
構造体変数の宣言
	item := struct {
		Name  string
		Price int
	}{
		Name:  "牛乳",
		Price: 150,
	}
2つのフィールドを持つ匿名の構造体を型とする変数 item を宣言して、初期化リストで初期化しています。
フィールドへのアクセス
	fmt.Println("品名は ", item.Name)
	fmt.Println("単価は ", item.Price)
構造体変数のフィールドの値を参照するには、構造体変数名とフィールド名を .(ピリオド)を中置した式を用います。
様々な表示フォーマット
	fmt.Println(item)
	fmt.Printf("%%v: %v\n", item)
	fmt.Printf("%%+v: %+v\n", item)
	fmt.Printf("%%#v: %#v\n", item)
実行結果
{牛乳 150}
%v: {牛乳 150}
%+v: {Name:牛乳 Price:150}
%#v: struct { Name string; Price int }{Name:"牛乳", Price:150}
fmt.Printlnに構造体変数を単純に渡しただけで、文字列化して表示されます。
fmt.Printfの %v 指定子 では fmt.Println と同じフォーマット。
%+v 指定子では、フィールド名付きで
%#v 指定子では、複合リテラルの書式で表示されます。

これらの、様々な表示フォーマットはデバッグの為に埋め込むときに役立ちます。

型定義

[編集]

型宣言は、識別子である型名を型に結びつけるものです。型宣言には、エイリアス宣言と型定義の2つの形式があります。[2]

構文
TypeDecl = "type" ( TypeSpec | "(" { TypeSpec ";" } ")" ) ;
TypeSpec = AliasDecl | TypeDef ;
エイリアス宣言
エイリアス宣言は、識別子を与えられた型に結びつけるものです。
構文
AliasDecl = identifier "=" Type ;

識別子のスコープ内では、型のエイリアスとして機能します。

型定義
型定義は、与えられた型と同じ基本的な型と操作を持つ新しい別個の型を作成し、識別子である型名をそれに結びつけます
構文
TypeDef = identifier [ TypeParameters ] ;

新しい型は、定義された型と呼ばれます。この型は、作成元の型も含め、他の型とは異なります。 Go1.18から、型定義も型パラメータを伴うことが出来る様になりました。

構造体型

[編集]

型定義の構文に構造体の構文を適用すると、構造体型の定義になります。

type Complex struct {
   real, image   float32
}

変数宣言

[編集]

変数宣言では、1つまたは複数の変数を作成し、対応する識別子を結合し、それぞれに型と初期値を与えます[3]

構文
VarDecl     = "var" ( VarSpec | "(" { VarSpec ";" } ")" ) ;
VarSpec     = IdentifierList ( Type [ "=" ExpressionList ] | "=" ExpressionList ) ;
type Complex struct {
   real, imag   float64
}
var cmplx Complex{ 2.4, 3.2 }
コード例
package main

import "fmt"

type Item struct {
	Name  string // 品名
	Price int    // 単価
}

func main() {
	item := new(Item)

	item.Name = "牛乳"
	item.Price = 150

	fmt.Println("品名は", item.Name)
	fmt.Println("単価は", item.Price)
}
実行結果
品名は 牛乳
単価は 150

配列

[編集]

配列とは、要素の種類と呼ばれる単一の型の要素の番号付けされた列のことです。要素の数は配列の長さと呼ばれ、決して負の値にはなりません[4]

構文
ArrayType   = "[" ArrayLength "]" ElementType ;
ArrayLength = Expression ;
ElementType = Type ;

スライス型

[編集]

https://golang.org/ref/spec#Slice_types スライスは、基礎となる配列の連続したセグメントの記述子であり、その配列の要素の番号付けされたシーケンスへのアクセスを提供します。スライスタイプは、その要素タイプの配列のすべてのスライスのセットを表します。要素の数はスライスの長さと呼ばれ、決して負ではありません。初期化されていないスライスの値はnilです[5]

構文
SliceType = "[" "]" ElementType ;

構造体スライスと構造体配列

[編集]

Goでは、他の言語の構造体配列の役割を表す方法に、構造体スライスと構造体配列があります。

スライスと配列の違いは、宣言で [ と ] の間に何もなければスライス。要素数か ... (初期化リストの要素数)が [ と ] の間にあったら配列です。 これだけの違いで、要素へのアクセスやfor文による反復など、多くの機能がスライスと配列に共通しています。 大きな違いは、スライスは実行時に要素数が変えられる点で、配列の要素数は宣言したときに確定します。

構造体スライス

[編集]
構造体スライス
package main

import "fmt"

func main() {
	collection := []struct {
		name  string `label:"品名"`
		price int    `label:"単価"`
	}{
		{name: "牛乳", price: 150},
		{name: "りんごジュース", price: 120},
	}
	for _, item := range collection {
		fmt.Println("商品名は ", item.name)
		fmt.Println("価格は ", item.price)
	}
	fmt.Printf("%%v = %v\n", collection)
	fmt.Printf("%%+v = %+v\n", collection)
	fmt.Printf("%%#v = %#v\n", collection)
	fmt.Printf("%T\n", collection)
}
実行結果
商品名は  牛乳
価格は  150
商品名は  りんごジュース
価格は  120
%v = [{牛乳 150} {りんごジュース 120}]
%+v = [{name:牛乳 price:150} {name:りんごジュース price:120}]
%#v = []struct { name string "label:\"品名\""; price int "label:\"単価\"" }{struct { name string "label:\"品名\""; price int "label:\"単価\"" }{name:"牛乳", price:150}, struct { name string "label:\"品名\""; price int "label:\"単価\"" }{name:"りんごジュース", price:120}}
[]struct { name string "label:\"品名\""; price int "label:\"単価\"" }

構造体配列

[編集]
構造体配列
package main

import "fmt"

func main() {
	collection := [...]struct {
		name  string `label:"品名"`
		price int    `label:"単価"`
	}{
		{name: "牛乳", price: 150},
		{name: "りんごジュース", price: 120},
	}
	for _, item := range collection {
		fmt.Println("商品名は ", item.name)
		fmt.Println("価格は ", item.price)
	}
	fmt.Printf("%%v = %v\n", collection)
	fmt.Printf("%%+v = %+v\n", collection)
	fmt.Printf("%%#v = %#v\n", collection)
	fmt.Printf("%T\n", collection)
}
実行結果
商品名は  牛乳
価格は  150
商品名は  りんごジュース
価格は  120
%v = [{牛乳 150} {りんごジュース 120}]
%+v = [{name:牛乳 price:150} {name:りんごジュース price:120}]
%#v = [2]struct { name string "label:\"品名\""; price int "label:\"単価\"" }{struct { name string "label:\"品名\""; price int "label:\"単価\"" }{name:"牛乳", price:150}, struct { name string "label:\"品名\""; price int "label:\"単価\"" }{name:"りんごジュース", price:120}}
[2]struct { name string "label:\"品名\""; price int "label:\"単価\"" }

脚註

[編集]
  1. ^ “Struct types ¶”. The Go Programming Language Specification. The Go website. (Jul 26, 2021). https://golang.org/ref/spec#Struct_types. 
  2. ^ “Type declarations ¶”. The Go Programming Language Specification. The Go website. (March 10, 2022). https://golang.org/ref/spec#Type_declarations. 
  3. ^ “Declarations_and scope ¶”. The Go Programming Language Specification. The Go website. (Jul 26, 2021). https://golang.org/ref/spec#Declarations_and_scope. 
  4. ^ “Array types ¶”. The Go Programming Language Specification. The Go website. (Jul 26, 2021). https://golang.org/ref/spec#Array_types. 
  5. ^ “Slice types ¶”. The Go Programming Language Specification. The Go website. (Jul 26, 2021). https://golang.org/ref/spec#Slice_types.