SwiftのRangeはHalf-Open(..<)の方を常用した方が良いかなと思った話

mono 
Swift・iOSコラム
3 min readSep 29, 2016

--

Swift 3.0で、Rangeの型が2つに分かれました。

  • Half-Open(..<)
  • Closed(…)

以下の記事に書いたとおり、両対応するには通常オーバーロードで2つメソッド用意する必要があって、少し面倒です。

ただ、ライブラリなどはともかく、通常のメソッド定義は、Half-Open(..<)の方だけ用意すれば良いかなと思ってきました。

Half-Open(..<)/Closed(…)が分かれている理由にも書いた通り、元々Closed(…)は構文の違いだけで内部的にはHalf-Open(..<)扱いされていた経緯がありましたし。また、以下の要件など無ければHalf-Open(..<)だけでこと足りますし。

Closed(…)のみ、その要素型のmax値を含めた書き方が出来る(0…Int.maxなど)

apple-reference-documentation://hs4GyoUE8n

NSRangeからRangeに変換するメソッドも、Half-Open(..<)用のものだけしか用意されていないことにも気付きました。

Half-Open(..<)の方が分かりやすく感じる

廃止されたCスタイルのforループは、通常以下のように、<=10ではなく<10でループカウントを指定していたのと同様、

for var i = 0; i < 10; i++ {
print("i: \(i)")
}

Rangeを使ったベターな書き方でも..<10の方が分かりやすいです。

for i in 0..<10 {
print("i: \(i)")
}

以下はあまり直感的に思えません。(文脈にもよりますが)

for i in 0...9 {
print("i: \(i)")
}

単純な引き算のみで要素数をカウント出来る

僕は、5..<10は10–5で5要素、5…9は9–5+1で5要素、といった感じでカウントしていますが、前者の方が直感的で好みです。

Pythonなどのスライスもそうなってる

例えば、PythonではRangeぽいものを1:3という風に表現しますが、これもHalf-Open(..<)です。

a = "12345"
a[1:3]
# → '23'

これ見ても慣習的に、Half-Open(..<)の方が分かりやすいかなと思いました。

本当にClosed(…)が必要な箇所でのみ使うようにした方が意図が明確になりそう

Closed(…)のみ、その要素型のmax値を含めた書き方が出来る(0…Int.maxなど)

こういったケースでのみClosed(…)を使って、それ以外の大半のケースではHalf-Open(..<)を使った方が分かりやすいと思いました。

結果、わざわざHalf-Open(..<)・Closed(…)用の2つのオーバロードを用意せずにHalf-Open(..<)だけで大抵は充分かな、と思った話でした。

--

--