Go言語における配列 (Arrays) とスライス (Slices) は、データを格納するための非常に重要なデータ構造です。それぞれの特徴と使い方を理解することは、Goを使いこなすために非常に大切です。この完全かつ包括的な記事では、配列とスライスの基本から応用までを詳しく解説します。
1. 配列 (Arrays)とは?
配列は、同じ型の値を複数格納するためのデータ構造です。配列のサイズは固定されており、一度作成された配列のサイズを変更することはできません。
1.1 配列の宣言と初期化
Goでは、配列は次のように宣言および初期化できます。
go// 配列の宣言と初期化
var arr [5]int = [5]int{1, 2, 3, 4, 5}
このコードでは、arrという名前の配列が宣言され、5つの整数が格納されています。配列のサイズは[5]で指定されています。
配列を宣言する際に、初期化子を使って初期値を設定することも可能です。例えば、次のように配列の一部のみを初期化することができます。
govar arr [5]int = [5]int{1, 2}
ここで、残りの配列要素はデフォルト値(0)で初期化されます。
1.2 配列の要素へのアクセス
配列の要素にアクセスするには、インデックスを使用します。Goの配列は0から始まるインデックスを使用します。
gofmt.Println(arr[0]) // 出力: 1
fmt.Println(arr[1]) // 出力: 2
1.3 配列の長さ
配列の長さは、len関数を使って取得できます。
gofmt.Println(len(arr)) // 出力: 5
1.4 配列の制限
配列のサイズは宣言時に決まるため、サイズを変更することはできません。例えば、[10]int型の配列に5つの要素を代入することはできますが、配列のサイズを動的に変更することはできません。
2. スライス (Slices)とは?
スライスは、配列の一部を抽出するための柔軟なデータ構造です。スライスは配列とは異なり、サイズが可変であり、配列のように静的ではなく動的に変更できます。
2.1 スライスの宣言と初期化
スライスは、次のように宣言および初期化できます。
go// スライスの宣言と初期化
var slice []int = []int{1, 2, 3, 4, 5}
このコードでは、sliceという名前のスライスが宣言され、5つの整数が格納されています。
2.2 スライスの長さと容量
スライスは配列と異なり、動的に要素を追加することができます。スライスの長さ(len)と容量(cap)を取得することができます。
gofmt.Println(len(slice)) // 出力: 5
fmt.Println(cap(slice)) // 出力: 5
容量はスライスが確保しているメモリの大きさを示します。スライスが追加で要素を格納できる容量を持っている場合、容量はlenより大きくなることがあります。
2.3 スライスの作成
スライスを作成するには、make関数を使うこともできます。make関数を使うと、指定した長さと容量のスライスを作成できます。
go// 長さ5、容量10のスライスを作成
slice := make([]int, 5, 10)
fmt.Println(len(slice)) // 出力: 5
fmt.Println(cap(slice)) // 出力: 10
2.4 スライスの要素へのアクセス
スライスの要素にも、配列と同じようにインデックスを使ってアクセスできます。
gofmt.Println(slice[0]) // 出力: 0 (初期値は0)
2.5 スライスの要素の追加
スライスは動的に要素を追加することができます。append関数を使うことで、新しい要素を追加できます。
go// スライスに要素を追加
slice = append(slice, 6)
fmt.Println(slice) // 出力: [0 0 0 0 0 6]
2.6 スライスのスライス
スライスは元のスライスの部分を取り出すことができます。これをスライスのスライスと呼びます。
go// スライスのスライス
subSlice := slice[1:4]
fmt.Println(subSlice) // 出力: [0 0 0]
3. 配列とスライスの違い
配列とスライスの主な違いは次の通りです。
- 配列は固定長:配列の長さは宣言時に決まり、その後変更できません。
- スライスは可変長:スライスは動的にサイズを変更でき、必要に応じて容量を増やすこともできます。
- メモリの管理:配列は宣言時に指定したメモリのサイズ分だけメモリが確保されますが、スライスは内部的に配列を参照しているため、要素の追加や削除が可能です。
4. スライスの背後にある配列
スライスは実際には配列を参照しています。スライスが要素を追加するたびに、新しい配列が作成される場合があります。このため、スライスをコピーする際には、新しい配列が作成され、元のスライスとの関係が切れることに注意が必要です。
4.1 スライスのコピー
スライスをコピーするには、copy関数を使います。
go// スライスをコピー
slice2 := make([]int, len(slice))
copy(slice2, slice)
fmt.Println(slice2) // sliceのコピー
5. 配列とスライスの使いどころ
- 配列は、サイズが変更されない固定長のデータセットを扱う場合に便利です。
- スライスは、動的に変更されるデータセットに対して使用します。データが追加される可能性がある場合や、サイズが不明な場合にスライスが適しています。
まとめ
Goの配列とスライスは、異なる用途に応じて使い分けることができます。配列はサイズが固定で、スライスは動的に変更できます。配列とスライスの特性を理解し、適切に使い分けることで、Goプログラミングがさらに効率的で強力になります。
