python スライス 範囲外はGoと何が違う?

要点

  • Pythonのリストでは、終了位置が範囲外でも存在する部分を返し、開始位置も超えると空リストを返した(出典: 自社の実測・2026-10-25)。
  • JavaScriptのslice()も、測定した範囲ではPythonと同じ結果だった(出典: 自社の実測・2026-10-25)。
  • Goでは、範囲内のスライス式は結果を返し、終了位置を超えた式はpanicで停止した(出典: 自社の実測・2026-10-25)。

範囲を超えても、エラーになるとは限らない

要素が3つあるデータから、開始位置を1、終了位置を100として一部分を取り出す。この指定に対して、存在する部分だけが返るのか、それとも処理が止まるのか。PythonとGoでは、今回の実測結果が分かれた。

スライスとは、開始位置と終了位置で指定した範囲の要素を取り出す操作のことだ。

Pythonのリスト[1, 2, 3]に対するa[1:100]は、エラーにならず[2, 3]を返した。一方、Goの[]int{1, 2, 3}に同じ範囲を指定した式は、panicを起こして停止した。見た目の似た範囲指定でも、長さを超えたときの扱いまで同じではない。

ここで区別したいのは、「処理が続いたこと」と「指定した範囲が意図どおりだったこと」である。Pythonでは結果が返るため、エラーの有無だけを見ても、範囲指定が適切だったかは判断できない。Goへ書き換える場面では、Pythonで処理が続いていた指定が、停止につながる可能性がある。

今回の記録は、PythonがPython 3.9.0、JavaScriptを実行したNode.jsがv22.23.4、Goがgo version go1.26.2 darwin/arm64という環境で得られたものだ。以下の結果は、この記録にある操作と対象に限って読む必要がある。

出典: 自社の実測(2026-10-25)

公式の記述と、実際に確認した範囲を分ける

Python公式リファレンスの「6.3.4. スライス」について、素材には、範囲が自動的に有効な範囲へ収まるよう調整される趣旨の説明が記録されている。ただし、公式本文の原文は収録されていないため、この説明を直接引用として扱うことはできない。

出典: https://docs.python.org/3/reference/expressions.html#slicings (取得日 2026-10-25)

Go言語仕様の「Slice expressions」からは、次の文言が収録されている。

the indices are in range if 0 <= low <= high <= len(a)… otherwise they are out of range

出典: https://go.dev/ref/spec#Slice_expressions (取得日 2026-10-25)

この引用は途中が省略された抜粋である。これだけを使って、あらゆる対象について境界の条件を説明し切ることはできない。本記事では、公式記述の引用と、具体的なコードで確認された挙動を分けて扱う。

また、素材にはJavaScriptの公式ドキュメントの引用は含まれていない。JavaScriptについて述べられるのは、収録された実測の対象と結果である。3言語の仕様全体を同じ資料の厚さで比較したものではない。

終了位置だけが範囲外の場合と、開始位置も超える場合

実測結果を、範囲の指定ごとに並べると次のようになる。「記録なし」の欄は、他の結果から補っていない。

言語・対象 範囲内の指定 終了位置が範囲外 開始位置も長さを超える指定
Pythonのリスト 記録なし a[1:100] → [2, 3] a[100:200] → []
JavaScriptの配列 記録なし a.slice(1, 100) → [2, 3] a.slice(100, 200) → []
Goのスライス a[1:3] → [2 3] a[1:100] → panicで停止 記録なし

Pythonでは、終了位置だけが長さを超えた場合と、開始位置も長さを超えた場合で、返る内容が異なった。前者では存在する部分が返り、後者では空リストになった。どちらもエラーにはならなかったが、同じ結果ではない。

素材にあるPythonの実物のコードと結果は、次のとおりだ。

a = [1, 2, 3]
print(a[1:100])    # [2, 3]
print(a[100:200])  # []

JavaScriptのslice()でも、この2つの範囲指定は同じ内容を返した。ただし、配列の添字による直接アクセスは別の操作である。記録ではa[100]がundefinedを返している。範囲外という言葉だけで、スライスの空配列と、添字アクセスのundefinedをひとまとめにしないようにしたい。

Goについて記録されたエラー文は、次のとおりである。

panic: runtime error: slice bounds out of range [:100] with capacity 3

この例では、存在する部分だけを返して続行する動きにはならなかった。比較の焦点は、返る要素の違いに加えて、範囲外の指定をした後に処理が続くかどうかにもある。

出典: 自社の実測(2026-10-25)

部分的な結果を受け入れるか、範囲の誤りを確かめるか

どちらの挙動を前提にコードを書くかは、取り出せた部分だけで処理を進めてよいかによって変わる。PythonとJavaScriptの実測では、終了位置が長さを超えても部分的な結果が返った。しかし、その結果が用途に合っているかは、エラーが出なかったことだけでは決まらない。

素材では、長さ100のデータを期待していたのに実際には3件しかなかった場合が、注意点として挙げられている。範囲外でも処理が続く挙動は、こうした想定との食い違いを、例外として知らせるものではない。必要なデータがそろっているかと、スライスが実行できるかは、分けて確かめたい。

Goでは、今回の範囲外指定がpanicとして表面化した。また、素材にはrecover()でpanicを捕まえた後、後続の処理で「続いている」と出力できた記録もある。これは範囲外指定が成功したという意味ではなく、発生したpanicを捕まえ、後続の処理へ進めたという結果である。

一方、この記録だけから「Goで対処する方法はこれしかない」と結論づけることはできない。確認できた方法と、選択肢のすべては別だからだ。移植時には、部分的な結果を受け入れていた箇所と、指定範囲の誤りを見つけたい箇所を確認する必要がある。

出典: 自社の実測(2026-10-25)

自分の環境で確かめる手順

Pythonについて同じ対象と範囲を確かめるなら、次のコマンドを実行する。これは読者の環境で確認するための手順であり、ここには新たな実行結果を載せていない。

python3 --version
python3 -c 'a = [1, 2, 3]; print(a[1:100]); print(a[100:200])'

版を確認したうえで、終了位置だけが範囲外の指定と、開始位置も長さを超える指定を見比べる。確認するときは、エラーが出たかだけでなく、返った内容が処理の意図に合っているかも見る。

今回の素材では、Pythonの文字列に対する範囲外スライスは測っていない。負のインデックスでの範囲外指定も未測定である。Goで開始位置だけが範囲外、終了位置が範囲内となる場合も、個別には確認されていない。リストで得られた結果を文字列へ広げたり、未測定の指定へ当てはめたりする根拠にはできない。

実際のコードを確かめる際には、素材で挙げられている空・1件・ちょうど境界という条件も、テストの観点になる。エラーが出ないことを正しさの判定にせず、必要な範囲と実際に得られる内容を照らし合わせることが、今回の比較から押さえたい点だ。

出典: 自社の実測(2026-10-25)

コメント

タイトルとURLをコピーしました