LoginSignup
19
16

More than 5 years have passed since last update.

Swift での Int 型 switch case の落とし穴(?)

Last updated at Posted at 2015-09-04

Swift の switch-case は範囲も使えるので大変便利ではありますが、Int 型でその「範囲」の使い方に意外な落とし穴がありました。例えば Playground で下記のコードを書いてみましょう:

let a = 0
switch a {
case Int.min ..< 0:
    print("負数")

case 0:
    print("零")

case 1 ... Int.max:
    print("正数")

default:
    fatalError("俺はプログラマをやめるぞ!")
}

まあこれなら結果はお察しの通り「零」が出力されますね。試しに let a = -1 に直してみればそれはまた「負数」が出力されますね。では、試しに let a = 1 に直してみれば結果はどうなるのでしょうか?

はい、正解は:ランタイムエラーでした!
スクリーンショット 2015-09-04 19.32.23.png

理由はいかにも単純で、実は case 文のあとに書く範囲はデフォルトでは Range にみなされてしまうのです。Swift における Range と言うのは Range.startIndex ..< Range.endIndex のように表現されますので、つまり最後は case 1 ... Int.max と書いているにも関わらず、実際は case 1 ..< Int.max.successor() 、つまり endIndexInt.max + 1 で処理されてしまうのです。当然、すでに Int.max だからそこから更にプラスすると表現できずランタイムエラーになってしまいます。

実はこれ、Stackoverflow にも気づいた人がいたのですがどうやらいかんせんアップルはこれを直す気がなさそうです。ですのでこれはどうにかソースコードで直すしかないのです。まあ一番簡単なやり方として

case 1 ..< Int.max, Int.max:

と、1 ..< Int.maxRange を作ってそこにもう一つ Int.max を追加する方法ですかね。もしくは「こんな書き方じゃあスマートじゃない!」と思うのなら、下記の書き方もできます:

case ClosedInterval(1 ... Int.max):

こう書けば強制的に Range ではなく ClosedIntervalcase の範囲を作りますので、これも一つの手です。

まあどのみち、どうせ Int 型なんだから最初から Interval で範囲作ってくれればいいのにアップル様。

p.s. あともうすでに case の中に全ての Int の場合を挙げたにも関わらずそれでも default 書かなきゃいけないアップル様のバカ!

19
16
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
19
16