[Swift] Rangeの罠

RangeのendIndexと聞いてどのような意味を思い浮かべるでしょうか?
0から4のRangeはどの範囲を示しているでしょうか?

今回はRangeのendIndexについて説明します。

forループする時に下記のように記述すると思います

for i in 0..<4 {
  // 0〜3までループ
} 

この時 0..<4は Arange<Int>を示しており、下記のrangeと同じ意味です
let range = Range<Int>(start:0,end:4)
※ ちなみに 0…4であれば Range<Int>(start:0,end:5) です。

このrangeのstartIndexとendIndexを調べると下記のようにイニシャライザで指定した値がそのまま入っています。

println("range \(range.startIndex)〜\(range.endIndex) ")
// range 0〜4

もちろんこのように生成したrangeをfor-inでループしてもリテラルで宣言したものと同様に
処理されます。

for i in range {
  // 0〜3までループ
}

で、何が言いたいのかと言うと、、
endIndexが4ならループ変数 i が4まで実行させるべきではないかと。
そのほうが分かりやすいよね。
javaのString.substringのendIndexと同じって思えば良いんだけど、そもそもjavaのそれも気に入らないので。。

 

百歩ゆずってループで使う場合にはこの仕様で良いとシヨウ(仕様と掛かってます/ドヤ)
でも何かしらの範囲を示す場合に混乱しますよね。
例えばこのような関数があったとして

// ティーンエイジの範囲を求める
func teenagerRange() -> Range<Int> {
  // ティーンって13才から19才だよね
  return Range<Int>(start:13,end:19)
}

この関数の戻り値を使ってティーンエイジャーを列挙すると

for age in teenagerRange() {
  print("age \(age)")
}

・・13から18でループされる、ナインティーンどこいった?

 
 

んー、まぁ1万歩ゆずって整数ならまだ良しとしよう。
DoubleとかでもRangeを作れるので

let range = Range<Double>(start:0.0,end:1.0) 

この場合、最終の値はなに?
0.9? 0.999999?

→ ForwardIndexTypeに準拠しないためDoubleのRangeは使えなくなりました。

もちろん (range.startIndex <= X && X < range.endIndex) という条件が正の場合とすれば良いのは分かるし、
この仕様の方がフィットする型があるのもわかります。(日時とかね)
でも 0 〜 0.9(just)までを示す事が出来ないと思いませんか?

Rangeってからには範囲を示すもので汎用的に使いたいんですけど、なんか使いづらい!
というか、メソッドによってRangeの意味が変わってしまう気がして気持ち悪い!
上限値、下限値を範囲に含めるか否かを示す値があれば良いんだけど、これが無いからだよね。
これは要注意だよ!

(2014-07-11) XCode6.0-beta3での仕様変更を反映

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です