Go言語(Golang)を効率的に学び、実戦で活用するためには、データ構造の基本である「配列」の理解が欠かせません。

プログラミング言語によって配列の扱いは異なりますが、Go言語における配列は非常に厳格なルールに基づいて設計されています。

本記事では、Go言語の配列の宣言方法から、初期化の手順、そして実務で役立つ操作方法までを詳しく解説します。

配列の仕組みを正しく理解することで、メモリ効率の良いプログラムや、バグの少ない堅牢なコードを記述できるようになります。

初心者の方でもスムーズに習得できるよう、コード例を交えながらステップバイステップで進めていきましょう。

Go言語における配列の基本概念

Go言語における配列とは、同じデータ型の要素を固定の長さで並べたデータ構造のことです。

一度宣言した配列のサイズを後から変更することはできません。

これは、配列の長さがその「型」の一部として扱われるためです。

例えば、[5]int[10]int は、たとえ中身が同じ int 型であっても、Go言語のシステム上では全く別の型として認識されます。

この特性により、配列はコンパイル時にメモリ使用量が確定するため、非常に高速に動作するというメリットがあります。

しかし、柔軟に要素数を増やしたい場合には「スライス」という別の仕組みを利用するのが一般的です。

まずは、すべての基礎となる固定長配列の扱い方をマスターしましょう。

配列の宣言とゼロ値

Go言語で配列を宣言する際の最も基本的な構文は、var 変数名 [要素数]型 という形式です。

変数を宣言した際、初期値を指定しない場合は、その型の「ゼロ値」で自動的に埋められます。

数値型であれば 0、文字列型であれば空文字 ""、論理型であれば false が格納されます。

Go
// 要素数5のint型配列を宣言
var numbers [5]int

// 要素数3のstring型配列を宣言
var labels [3]string

このとき、numbers の中身はすべて 0 になり、labels の中身はすべて空文字になります。

実行結果を確認してみましょう。

Go
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言語には、状況に応じた柔軟な初期化の記法が用意されています。

配列リテラルによる初期化

波括弧 {} を使用して、宣言時に値を指定する方法が一般的です。

Go
// 宣言と同時に値を代入
var fruits [3]string = [3]string{"Apple", "Banana", "Cherry"}

// 短縮変数宣言を利用する場合
prices := [4]int{100, 200, 300, 400}

この方法を用いることで、プログラムの可読性を高めることができます。

要素数を省略する初期化(…)

配列の要素数を手動で数えるのが面倒な場合、暗黙的に要素数を決定させる ... 記法が便利です。

Go
// コンパイラが要素数を3と判断する
colors := [...]string{"Red", "Green", "Blue"}

この記法を使用しても、生成されるのはあくまで「固定長」の配列であり、宣言後のサイズ変更はできない点に注意してください。

特定のインデックスを指定した初期化

特定の場所だけに値を入れ、他をゼロ値にしたい場合には、インデックスを指定する記法が使えます。

Go
// インデックス0と4だけを指定して初期化
specialArray := [5]int{0: 100, 4: 500}

この場合、間のインデックス 1、2、3 は自動的に 0 になります。

実行結果
[100 0 0 0 500]

配列の要素へのアクセスと更新

配列の各要素にアクセスするには、変数名[インデックス] という形式を使用します。

プログラミングの一般的なルール通り、インデックスは 0 から始まります

Go
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() 関数が返す値は、配列の型で定義された固定の長さです。

Go
vals := [10]int{1, 2, 3}
fmt.Println(len(vals)) // 出力は 10

たとえ実際に格納した値が3つだけであっても、配列のサイズ自体が 10 であれば、len() は 10 を返します。

for文とrangeによる反復処理

配列の全要素を順番に処理する場合、for 文を使用するのが最も一般的です。

特に range キーワードを使用すると、インデックスと値を同時に取得できるため、非常に簡潔に記述できます。

Go
items := [3]string{"ペン", "ノート", "消しゴム"}

// rangeを使ったループ
for index, value := range items {
    fmt.Printf("%d番目のアイテム: %s\n", index, value)
}

もしインデックスが必要ない場合は、ブランク識別子 _ を使って破棄することができます。

Go
for _, value := range items {
    fmt.Println("値のみ取得:", value)
}

多次元配列の宣言と利用

Go言語では、配列の中に配列を格納することで「多次元配列」を表現できます。

行列のようなデータを扱う際に役立ちます。

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が表示される

初期化を一度に行う場合は、以下のようになります。

Go
grid := [2][2]string{
    {"A1", "A2"},
    {"B1", "B2"},
}

配列は「値」であるという重要な性質

他の多くの言語(CやJava、JavaScriptなど)では、配列を別の変数に代入すると、メモリ上の同じ場所を参照することが多いです。

しかし、Go言語の配列は「値」として扱われます

つまり、配列を別の変数に代入したり、関数に引数として渡したりすると、配列のコピーが作成されます。

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プログラミングの世界が広がっていくはずです。