【Swift/XCode】swift配列のindex, startIndex, endIndex ?インデックスが0にリセットされる言語とそうでない言語?

SwiftUI

count – 1 が最後のインデックスかなと思ったら endIndexなるものがあるので。使おうかなと思ったら
endIndex は 最後のindex + 1だった。ほー
そこで少し見たら ArrayではなくArraySliceになるとインデックスとcountがずれる可能性があると。


スライス(切り出し)を行った際に、インデックスが 0 からリセットされる言語」「元のインデックスが維持される言語(リセットされない言語)」 を明確に分類して整理しました。

結論から言うと、「Swiftのようにスライス後も元のインデックス(1や2…)がそのまま残る言語」は非常に珍しい(例外的) です。ほとんどの言語は 0 にリセットされるか、コピーを作成して 0 始まりになります。

1. 0 にリセットされる言語(主流)

スライスを行っても、切り出したビュー(またはコピー)の先頭インデックスは必ず 0 から始まります

そのため、これらの言語では 0length - 1(または len - 1)を基準に処理してもインデックス範囲外エラーにはなりません。

🔹 参照(ビュー)を共有するが 0 リセットされる言語

メモリのコピーを作らず軽量に参照だけを切り出しますが、先頭は 0 に再マッピングされる仕様です。

  • Go言語
    • s := array[1:3] とすると、s[0] が元の array[1] を指します。
  • Rust
    • let slice = &vec[1..3]; とすると、slice[0] が元の vec[1] を指します。
  • C++ (std::span / std::string_view)
    • std::span sub = span.subspan(1, 2); とすると、sub[0] が切り出し先頭要素になります。
  • Kotlin (List.subList)
    • val sub = list.subList(1, 3) とすると、ビュー(参照)ですが sub[0] でアクセスします。
  • Java (List.subList)
    • List<String> sub = list.subList(1, 3); とすると、ビューですが sub.get(0) でアクセスします。

🔹 コピー(新しい配列)を作成して 0 リセットされる言語

参照の共有すら発生せず、メモリ上に「新しい配列」を生成するため、当然 0 始まりになります。

  • Python (list[1:3])
  • JavaScript / TypeScript (array.slice(1, 3))
  • Ruby (array[1..2])
  • PHP (array_slice($array, 1, 2)) ※デフォルト挙動

2. 元のインデックスが維持される(0 にリセットされない)言語・仕様

スライスしても「元の配列のインデックス番号」をそのまま保持するため、0length - 1 を盲信するとクラッシュ・バグになる言語です。

  • Swift (ArraySlice)
    • let slice = array[1...2] とすると、slice[1] から始まります(slice[0] は存在しない)。
  • PHP (array_slice で第4引数に true を渡した場合)
    • array_slice($array, 1, 2, true) とすると、元のキー/インデックス(1や2…)がそのまま維持されます。
  • Julia (@views または 部分配列)
    • 標準の切り出しはコピーで 1 始まり(Juliaは1始まりの言語)ですが、view 機能(@views)を使うと、元の多次元配列などのインデックス範囲(例: 3:5)をそのまま維持する設定が可能です。

一覧比較テーブル

言語操作 / 型スライスの実体先頭インデックスcount – 1 や 0 判定の安全性
SwiftArraySlice参照ビュー元のまま (例: 1)危険 (startIndex 必須)
Go[]T (Slice)参照ビュー0 にリセット⭕️ 安全
Rust&[T] (Slice)参照ビュー0 にリセット⭕️ 安全
C++std::span参照ビュー0 にリセット⭕️ 安全
Java / KotlinsubList()参照ビュー0 にリセット⭕️ 安全
Pythonlist[a:b]新規コピー0 にリセット⭕️ 安全
JavaScriptarray.slice()新規コピー0 にリセット⭕️ 安全

なぜこんな違いがあるのか?

  • 他の言語(Go, Rust, Python等):「切り出したもの(スライス)は、それ自体を1つの独立したリスト/配列として扱いたい」という直感的な扱いやすさを重視しています。
  • Swift:「元の配列とスライスされた部分で、同じインデックス番号を使って相互に位置を追跡・参照できるようにする」という、アルゴリズムの厳密性と安全性を最重視した独自の設計思想を採用しています。

そのため、他言語から Swift に来た開発者ほど、この ArraySlice の「インデックスが維持される挙動」に引っかかりやすくなっています。Swift を扱う際だけは、特に startIndex / endIndex の意識を強く持っておくのが正解です。

なかなか面白いですね?

お気軽にコメントください!

スパム対応のためコメント認証に数日かかることがありますが、お気軽にコメントいただけると嬉しいです^^

コメント

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