Goにおける「panic: runtime error: slice bounds out of range」の修正方法

beginner🔷 Go2026-06-14| Go (Golang) ランタイム、すべてのオペレーティングシステム

Error Message

panic: runtime error: slice bounds out of range [:5] with length 3
#golang#スライス#パニック#デバッグ#ランタイム

問題:境界を超えたスライス操作Goのスライスは強力ですが、譲れないルールが1つあります。実際の長さを超えてアクセスしたりスライスしたりすることはできません。元のサイズより大きいサブスライスを取得しようとすると、Goランタイムは非常ブレーキをかけます。メモリ破損を防ぐためにパニックを発生させるのです。これは、プログラムがゴミデータを読み取るのを防ぐガードレールのようなものだと考えてください。

通常、これは誤った想定が原因で発生します。例えば、APIが100件のログを返すと期待していたのに、実際には3件しか返ってこなかった場合などです。コードがすぐに最初の10項目を処理しようとすると、壁に突き当たります。

実際のエラーメッセージ```

panic: runtime error: slice bounds out of range [:5] with length 3


このシナリオでは、プログラムは開始からインデックス5(`[:5]`)までのスライスを試みました。しかし、スライスには3つの要素しかありませんでした。インデックス3、4、5は存在しないため、プログラムは即座にクラッシュしました。
## クラッシュの再現以下は、この失敗を再現するスニペットです。このパターンは、開発者がソースのサイズを確認せずにデータを「プレビュー」しようとしたときによく見られます。

package main

import "fmt"

func main() { // シミュレーション: データベースやAPIから取得したデータ userIDs := []string{"user_1", "user_2", "user_3"}

// 目標: 上位5名のユーザーを表示
// この行でパニックが発生します
topFive := userIDs[:5]

fmt.Println(topFive)

}


Running `go run main.go`を実行すると、`slice bounds out of range`パニックが発生します。`len(userIDs)`が3しかないため、インデックス5は指定不可能なターゲットとなり、プログラムが終了します。
## 修正方法### 1. 定番の長さチェック最も信頼できる修正方法は、スライスを操作する前にその長さを確認することです。これはシンプルで防御的であり、すべてのGoバージョンで動作します。常に、実際に利用可能なデータに基づいて「終了」インデックスを計算してください。

limit := 5 if len(userIDs) < limit { limit = len(userIDs) }

topFive := userIDs[:limit] fmt.Println(topFive)


### 2. モダンなアプローチ (Go 1.21以降)Go 1.21以降を使用している場合は、組み込みの`min`関数を使うことで、よりすっきりと記述できます。比較ロジックを1行で読みやすく処理できます。

// minのためのインポートは不要 limit := min(5, len(userIDs)) topFive := userIDs[:limit]


### 3. 安全なスライス用ユーティリティの作成大量のデータを処理するプロジェクトでは、ヘルパー関数を作成することでコードの重複を防ぎ、ビジネスロジックを整理された状態に保つことができます。

func safeSlice(s []string, start, end int) []string { if start > len(s) { return nil } if end > len(s) { end = len(s) } return s[start:end] }

// 使用例: topFive := safeSlice(userIDs, 0, 5)


## スライシング vs 直接アクセスまた、`index out of range [5] with length 3`というエラーに遭遇することもあります。見た目は似ていますが、これはスライシングではなく、直接アクセス(例:`id := userIDs[5]`)の際に発生します。修正方法は同じです。特定のインデックスにアクセスする前に、必ず`len(slice)`を確認してください。1回のテストで動いたからといって、そのインデックスが常に存在すると仮定してはいけません。
## 検証戦略修正をデプロイする前に、ロジックが万全であることを確認するため、以下の3つの特定のシナリオをテストしてください。
- **大きな入力:** スライスに50個の項目がある場合、`[:5]`は正確に5個を返すべきです。- **小さな入力:** スライスに2個の項目がある場合、`[:5]`は5個ではなく2個の項目を返すべきです。- **空の入力:** スライスが`nil`または長さ0の場合、コードはクラッシュせずに空のスライスを返すべきです。将来のリファクタリング時のデグレードを防ぐために、これらのチェックを`go test`スイートに組み込みましょう。
## 本番環境への教訓- **入力を信頼しない:** 外部APIやデータベースから取得するデータの長さを決して信用しないでください。- **Rangeに任せる:** 可能な限り`for i, val := range slice`を使用してください。これにより、境界の安全性が自動的に処理されます。- **早期に失敗させる:** スライスが空で関数を続行できない場合は、即座にエラーを返してください。nilや空のスライスをロジックの奥深くまで入り込ませないようにしましょう。- **チェックを自動化する:** CI/CDパイプラインで`golangci-lint`を使用し、本番環境に到達する前に潜在的な範囲外エラーを特定しましょう。

Related Error Notes