Go言語(Golang)を効率的に学び、実戦で活用するためには、データ構造の基本である「配列」の理解が欠かせません。
プログラミング言語によって配列の扱いは異なりますが、Go言語における配列は非常に厳格なルールに基づいて設計されています。
本記事では、Go言語の配列の宣言方法から、初期化の手順、そして実務で役立つ操作方法までを詳しく解説します。
配列の仕組みを正しく理解することで、メモリ効率の良いプログラムや、バグの少ない堅牢なコードを記述できるようになります。
初心者の方でもスムーズに習得できるよう、コード例を交えながらステップバイステップで進めていきましょう。
Go言語における配列の基本概念
Go言語における配列とは、同じデータ型の要素を固定の長さで並べたデータ構造のことです。
一度宣言した配列のサイズを後から変更することはできません。
これは、配列の長さがその「型」の一部として扱われるためです。
例えば、[5]int と [10]int は、たとえ中身が同じ int 型であっても、Go言語のシステム上では全く別の型として認識されます。
この特性により、配列はコンパイル時にメモリ使用量が確定するため、非常に高速に動作するというメリットがあります。
しかし、柔軟に要素数を増やしたい場合には「スライス」という別の仕組みを利用するのが一般的です。
まずは、すべての基礎となる固定長配列の扱い方をマスターしましょう。
配列の宣言とゼロ値
Go言語で配列を宣言する際の最も基本的な構文は、var 変数名 [要素数]型 という形式です。
変数を宣言した際、初期値を指定しない場合は、その型の「ゼロ値」で自動的に埋められます。
数値型であれば 0、文字列型であれば空文字 ""、論理型であれば false が格納されます。
// 要素数5のint型配列を宣言
var numbers [5]int
// 要素数3のstring型配列を宣言
var labels [3]string
このとき、numbers の中身はすべて 0 になり、labels の中身はすべて空文字になります。
実行結果を確認してみましょう。
package main
import "fmt"
func main() {
var numbers [5]int
fmt.Printf("値: %v\n", numbers)
fmt.Printf("長さ: %d\n", len(numbers))
}
値: [0 0 0 0 0]
長さ: 5
このように、宣言しただけでメモリが確保され、安全な初期値で満たされるのがGo言語の特徴です。
配列の初期化方法
配列を宣言すると同時に特定の値を代入することを「初期化」と呼びます。
Go言語には、状況に応じた柔軟な初期化の記法が用意されています。
配列リテラルによる初期化
波括弧 {} を使用して、宣言時に値を指定する方法が一般的です。
// 宣言と同時に値を代入
var fruits [3]string = [3]string{"Apple", "Banana", "Cherry"}
// 短縮変数宣言を利用する場合
prices := [4]int{100, 200, 300, 400}
この方法を用いることで、プログラムの可読性を高めることができます。
要素数を省略する初期化(…)
配列の要素数を手動で数えるのが面倒な場合、暗黙的に要素数を決定させる ... 記法が便利です。
// コンパイラが要素数を3と判断する
colors := [...]string{"Red", "Green", "Blue"}
この記法を使用しても、生成されるのはあくまで「固定長」の配列であり、宣言後のサイズ変更はできない点に注意してください。
特定のインデックスを指定した初期化
特定の場所だけに値を入れ、他をゼロ値にしたい場合には、インデックスを指定する記法が使えます。
// インデックス0と4だけを指定して初期化
specialArray := [5]int{0: 100, 4: 500}
この場合、間のインデックス 1、2、3 は自動的に 0 になります。
[100 0 0 0 500]
配列の要素へのアクセスと更新
配列の各要素にアクセスするには、変数名[インデックス] という形式を使用します。
プログラミングの一般的なルール通り、インデックスは 0 から始まります。
package main
import "fmt"
func main() {
var arr [3]int
// 値の代入
arr[0] = 10
arr[1] = 20
arr[2] = 30
// 値の参照
fmt.Println("1番目の要素:", arr[0])
}
存在しないインデックス(例:要素数3の配列に対して arr[3])にアクセスしようとすると、コンパイルエラーまたは実行時エラーが発生します。
Go言語は境界チェックを厳格に行うため、安全性が高い設計となっています。
配列の長さを取得する
配列にいくつの要素が含まれているかを知るには、組み込みの len() 関数を使用します。
len() 関数が返す値は、配列の型で定義された固定の長さです。
vals := [10]int{1, 2, 3}
fmt.Println(len(vals)) // 出力は 10
たとえ実際に格納した値が3つだけであっても、配列のサイズ自体が 10 であれば、len() は 10 を返します。
for文とrangeによる反復処理
配列の全要素を順番に処理する場合、for 文を使用するのが最も一般的です。
特に range キーワードを使用すると、インデックスと値を同時に取得できるため、非常に簡潔に記述できます。
items := [3]string{"ペン", "ノート", "消しゴム"}
// rangeを使ったループ
for index, value := range items {
fmt.Printf("%d番目のアイテム: %s\n", index, value)
}
もしインデックスが必要ない場合は、ブランク識別子 _ を使って破棄することができます。
for _, value := range items {
fmt.Println("値のみ取得:", value)
}
多次元配列の宣言と利用
Go言語では、配列の中に配列を格納することで「多次元配列」を表現できます。
行列のようなデータを扱う際に役立ちます。
// 2行3列のint型多次元配列
var matrix [2][3]int
matrix[0] = [3]int{1, 2, 3}
matrix[1] = [3]int{4, 5, 6}
fmt.Println(matrix[1][2]) // 6が表示される
初期化を一度に行う場合は、以下のようになります。
grid := [2][2]string{
{"A1", "A2"},
{"B1", "B2"},
}
配列は「値」であるという重要な性質
他の多くの言語(CやJava、JavaScriptなど)では、配列を別の変数に代入すると、メモリ上の同じ場所を参照することが多いです。
しかし、Go言語の配列は「値」として扱われます。
つまり、配列を別の変数に代入したり、関数に引数として渡したりすると、配列のコピーが作成されます。
a := [3]int{1, 2, 3}
b := a // aの内容がbに丸ごとコピーされる
b[0] = 100
fmt.Println("a:", a)
fmt.Println("b:", b)
a: [1 2 3]
b: [100 2 3]
このように、コピーされた側の b を書き換えても、元の a には影響しません。
大きな配列を頻繁にコピーするとパフォーマンスに影響を与える可能性があるため、大きなデータを扱う際はポインタを使用するか、スライスを利用するのが一般的です。
配列とスライスの比較
Go言語を学ぶ上で避けて通れないのが、配列とスライスの違いです。
実務では配列よりもスライスが圧倒的に多く使われますが、そのベースには常に配列が存在しています。
| 特徴 | 配列 (Array) | スライス (Slice) |
|---|---|---|
| サイズ | 固定(宣言時に決定) | 可変(動的に変更可能) |
| 型定義 | [5]int (サイズを含む) | []int (サイズを含まない) |
| 値の渡し方 | 値渡し (コピーされる) | 参照渡しに近い (裏側の配列を共有) |
| 主な用途 | メモリ配置を固定したい特殊なケース | 一般的なリスト操作全般 |
配列は「土台」であり、スライスはその「土台の上を自由に動く窓」のようなイメージです。
配列を使用する際の注意点
配列を扱う際に初心者が陥りやすいポイントがいくつかあります。
まず、配列のサイズは必ず定数でなければならないという点です。
変数を使って var a [n]int(nは変数)のように宣言することはできません。
動的なサイズが必要な場合は、迷わずスライスを使用しましょう。
また、関数の引数に配列を指定する場合、型が厳密にチェックされるため、サイズが異なる配列を渡すことは不可能です。
func process(data [5]int) という関数に [10]int を渡そうとするとコンパイルエラーになります。
汎用的な関数を作りたい場合は、スライスを受け取るように設計するのがGoのベストプラクティスです。
まとめ
Go言語の配列は、サイズが固定された型安全なデータ構造です。
var による宣言、リテラルによる初期化、そして ... を使った省略記法など、多様な宣言方法を理解することが第一歩です。
配列は「値」として振る舞い、代入時にコピーが発生するという特性は、プログラムの挙動を左右する重要な知識となります。
柔軟性が必要な場面ではスライスに主役を譲ることが多いですが、Goのメモリ管理やデータ構造の基本を理解するために、配列のマスターは避けて通れません。
まずは小さなコードを自分で書いて実行し、配列の挙動を体感してみてください。
基礎を固めることで、より高度なGoプログラミングの世界が広がっていくはずです。
