配列

Go言語の配列と構造体について解説

Go言語では、配列を使って同じ型のデータを効率的に管理できます。

一方、構造体は異なる型のデータをひとまとめにするため、柔軟なプログラム設計をサポートします。

この記事では、基本的な使い方を具体例とともに解説します。

Go言語の配列の基礎

配列の宣言と初期化

Go言語では、配列は固定長のデータ構造として用いられます。

配列の宣言は、変数名に続いて型と長さを指定する形で行います。

例えば、整数型の配列を宣言する場合は、以下のように記述します。

package main
import "fmt"
func main() {
	// int型の要素を5個持つ配列numsを宣言
	var nums [5]int
	// 配列を初期化する方法1: 個別に代入
	nums[0] = 10
	nums[1] = 20
	nums[2] = 30
	nums[3] = 40
	nums[4] = 50
	fmt.Println("Individual assignment:", nums)
	// 配列を初期化する方法2: 宣言時に初期値を設定
	letters := [3]string{"a", "b", "c"}
	fmt.Println("Literal initialization:", letters)
}
Individual assignment: [10 20 30 40 50]
Literal initialization: [a b c]

このように、配列を宣言すると固定されたサイズの領域が確保されます。

宣言時に初期値を指定することで、読みやすいコードを書くことができます。

配列の長さと容量

配列の長さは、宣言時に決定され、変更することができません。

たとえば、配列の長さを知りたい場合は、標準パッケージlenを使用します。

package main
import "fmt"
func main() {
	// 要素数が4の文字列配列を宣言
	colors := [4]string{"red", "green", "blue", "yellow"}
	// len関数で配列の長さを取得
	fmt.Println("Length of colors array:", len(colors))
}
Length of colors array: 4

また、Goの配列では容量という概念は固定長の配列の場合には長さと同義となります。

切り出し操作で作成されるスライスの場合は、容量と長さが個別に存在しますが、今回は配列の基本について説明します。

配列の操作方法

要素の取得と更新

配列に格納されている要素には、インデックスを指定してアクセスします。

インデックスは0から始まるため、先頭の要素はarray[0]で取得できます。

また、インデックスを指定して新しい値を設定することも可能です。

package main
import "fmt"
func main() {
	// 整数配列の宣言と初期化
	scores := [3]int{85, 90, 95}
	// 要素の取得
	firstScore := scores[0]
	fmt.Println("First score:", firstScore)
	// 要素の更新
	scores[1] = 100
	fmt.Println("Updated scores:", scores)
}
First score: 85
Updated scores: [85 100 95]

ループ処理による走査

配列の全要素に対して処理を行うには、ループ処理が便利です。

Go言語では、forループやrangeキーワードを用いて配列の各要素を走査できます。

package main
import "fmt"
func main() {
	// 配列の宣言と初期化
	fruits := [4]string{"apple", "banana", "cherry", "date"}
	// forループとrangeによる走査
	for index, fruit := range fruits {
		fmt.Printf("Index %d: %s\n", index, fruit)
	}
}
Index 0: apple
Index 1: banana
Index 2: cherry
Index 3: date

部分配列の生成

配列自体は固定長であるため、部分配列を直接切り出すことはできませんが、配列からスライスを生成することで、部分的なデータを扱うことが可能です。

スライスは配列の一部を参照する柔軟なデータ構造となります。

package main
import "fmt"
func main() {
	// 配列の宣言と初期化
	numbers := [6]int{0, 1, 2, 3, 4, 5}
	// 配列からスライスを生成: numbers[2]からnumbers[4]までを参照
	subSlice := numbers[2:5]
	fmt.Println("Sub-slice:", subSlice)
}
Sub-slice: [2 3 4]

スライスを用いると、配列から必要な部分だけを柔軟に扱うことができ、他の計算や制御構文と組み合わせる際に役立ちます。

Go言語の構造体の基礎

構造体の定義と初期化

Go言語の構造体は、関連する複数のデータをひとまとめにするためのデータ構造です。

構造体はtypeキーワードを用いて定義し、実際に使用する際は変数として生成します。

package main
import "fmt"
// Person構造体の定義
type Person struct {
	Name string
	Age  int
}
func main() {
	// 構造体の初期化方法1: フィールド名を指定して初期化
	personA := Person{
		Name: "Taro",
		Age:  30,
	}
	fmt.Println("Person A:", personA)
	// 初期化方法2: 順番に値を並べる方法(フィールド名は省略)
	personB := Person{"Hanako", 25}
	fmt.Println("Person B:", personB)
}
Person A: {Taro 30}
Person B: {Hanako 25}

構造体を定義することで、関連性のあるデータをひと纏めにし、プログラムの読みやすさと保守性を向上させることができます。

フィールドの宣言方法

構造体のフィールドは任意の型を指定して宣言できます。

基本型や配列、さらには他の構造体との組み合わせも可能です。

これにより、より複雑なデータ構造を組み立てることが可能となります。

例えば、以下のコードではAddress構造体を定義し、それをPerson構造体のフィールドとして利用しています。

package main
import "fmt"
// Address構造体の定義
type Address struct {
	City    string
	ZipCode string
}
// Person構造体の定義
type Person struct {
	Name    string
	Age     int
	Address Address // 他の構造体をフィールドとして使用
}
func main() {
	// 内部構造体の初期化
	myAddress := Address{
		City:    "Tokyo",
		ZipCode: "100-0001",
	}
	// Person構造体の初期化
	person := Person{
		Name:    "Ken",
		Age:     28,
		Address: myAddress,
	}
	fmt.Println("Person information:", person)
}
Person information: {Ken 28 {Tokyo 100-0001}}

このように、構造体を組み合わせることで、実世界の複雑な情報を自然な形で表現することができます。

構造体の利用例と操作方法

構造体におけるメソッドの実装

Go言語では、構造体に対してメソッドを定義することが可能です。

メソッドはレシーバを持つ関数として定義され、構造体のデータを操作するために活用されます。

以下の例では、Person構造体に対してGreetメソッドを実装しています。

package main
import "fmt"
// Person構造体の定義
type Person struct {
	Name string
	Age  int
}
// Person構造体のGreetメソッド
func (p Person) Greet() string {
	return "Hello, my name is " + p.Name
}
func main() {
	person := Person{"Yuki", 32}
	// メソッドの呼び出し
	greeting := person.Greet()
	fmt.Println(greeting)
}
Hello, my name is Yuki

メソッドを実装することで、構造体のデータに対する操作を自然な形でカプセル化でき、コードの再利用性や可読性が向上します。

構造体の値操作と更新

構造体のフィールドは、インスタンス生成後に個別に更新することが可能です。

以下の例では、Person構造体のフィールドを直接更新する方法と、ポインタレシーバを用いて更新する方法を紹介します。

package main
import "fmt"
// Person構造体の定義
type Person struct {
	Name string
	Age  int
}
// UpdateAgeはポインタレシーバを用いてフィールドを更新するメソッド
func (p *Person) UpdateAge(newAge int) {
	p.Age = newAge
}
func main() {
	// インスタンス生成と直接更新
	person := Person{"Sora", 20}
	fmt.Println("Before update:", person)
	// ポインタレシーバのメソッドを呼び出してAgeフィールドを更新
	person.UpdateAge(21)
	fmt.Println("After update:", person)
}
Before update: {Sora 20}
After update: {Sora 21}

このように、必要に応じて構造体のフィールドを操作することで、プログラム内でのデータ更新が容易になります。

配列と構造体の組み合わせ活用例

構造体の配列による管理方法

配列と構造体を組み合わせると、例えば複数のデータを効率的に管理できるようになります。

ここでは、複数のPersonを配列として宣言し、要素ごとにアクセスするサンプルコードを示します。

package main
import "fmt"
// Person構造体の定義
type Person struct {
	Name string
	Age  int
}
func main() {
	// Person構造体の配列を宣言し初期化
	people := [3]Person{
		{"Alice", 30},
		{"Bob", 25},
		{"Charlie", 35},
	}
	// 配列内の各要素に対して情報を出力する
	for i, p := range people {
		fmt.Printf("Person %d: Name = %s, Age = %d\n", i, p.Name, p.Age)
	}
}
Person 0: Name = Alice, Age = 30
Person 1: Name = Bob, Age = 25
Person 2: Name = Charlie, Age = 35

配列内の構造体の走査と操作

配列内の構造体に対してループ処理を行い、各要素の更新や特定の条件に基づいた操作を実施することが可能です。

以下は、年齢が30以上のメンバーだけを抽出して情報を出力する例です。

package main
import "fmt"
// Person構造体の定義
type Person struct {
	Name string
	Age  int
}
func main() {
	people := [4]Person{
		{"Dave", 28},
		{"Eve", 31},
		{"Frank", 29},
		{"Grace", 33},
	}
	// 条件に基づいて情報を出力する
	for _, p := range people {
		if p.Age >= 30 {
			fmt.Printf("%s is %d years old.\n", p.Name, p.Age)
		}
	}
}
Eve is 31 years old.
Grace is 33 years old.

複雑なデータ構造の実装例

配列と構造体を組み合わせることで、より複雑なデータ構造を実現できます。

ここでは、複数の従業員情報を持つ部署(Department)を例にします。

部署は複数の従業員(Employee)を管理するため、構造体のスライスをフィールドとして利用します。

package main
import "fmt"
// Employee構造体の定義
type Employee struct {
	Name     string
	Position string
}
// Department構造体の定義。EmployeesはEmployee構造体のスライス
type Department struct {
	DeptName  string
	Employees []Employee
}
func main() {
	// Department構造体の初期化
	dept := Department{
		DeptName: "Development",
		Employees: []Employee{
			{"John", "Engineer"},
			{"Emma", "Designer"},
			{"Mike", "Manager"},
		},
	}
	// 部署名の出力
	fmt.Println("Department:", dept.DeptName)
	// 各従業員の情報を出力
	for i, employee := range dept.Employees {
		fmt.Printf("Employee %d: Name = %s, Position = %s\n", i, employee.Name, employee.Position)
	}
}
Department: Development
Employee 0: Name = John, Position = Engineer
Employee 1: Name = Emma, Position = Designer
Employee 2: Name = Mike, Position = Manager

この例では、部署と従業員の情報を組み合わせたデータ構造を作成し、リスト形式で出力しています。

必要に応じて、更に複雑なデータ操作や更新も可能です。

まとめ

この記事では、Go言語の配列の宣言・初期化、配列操作、構造体の定義・初期化やメソッド実装、そして両者の組み合わせ活用例についてサンプルコードを交えながら解説しました。

基本的な操作から高度な組み合わせの実例まで、実践的な内容を網羅しており、各操作の概要を理解できる内容となっています。

ぜひ、実際にコードを書いて試しながら、知識を自分のものにしてみてください。

関連記事

Back to top button
目次へ