概要
Swiftのswitch文では、通常caseまたはdefaultを1つしか通りません。
しかし以降のcaseも続けて実行したい場合には、 fallthroughを使うことで実現することが可能です
これは 判定値がcaseに当てはまらなかったとしても実行されます。
func testFallthrough(x: Int) {
switch (x) {
case 0:
print("zero")
fallthrough
case 1: // x != 1 だがfallthroughしているので実行される
print("one")
fallthrough
default: // x != default だがfallthroughしているので実行される
print("non-binary")
}
}
print(testFallthrough(x: 0)) // "zero" "one" "non-binary" が出力される
やりたかったこと
これを利用し、 ある2次元の座標点Pが、事前に定義した各領域に含まれるかどうかを判定するため、switch文で当たり判定の算出を試みました
例として、2つの領域 rightAbove
と leftBelow
を定義し、その中にPが含まれている場合にその情報を配列で返したいとします。
座標が領域に含まれることをチェックするcase文では、 whereにより判定をかけています。
ここで自分は**「fallthroughはcaseにある条件を無視するのであってwhere句の条件は無視されない」**と勝手に思い込んで、以下のような実装をしてしまいました。
enum AreaType: String {
case rightAbove = "右上"
case leftBelow = "左下"
}
func checkHitAreas(x: Int, y: Int) -> [AreaType] {
var hitAreas: [AreaType] = []
switch (x, y) {
case let (x, y) where -5...10 ~= x && -5...10 ~= y:
hitAreas.append(.rightAbove)
fallthrough
case let (x, y) where -10...5 ~= x && -10...5 ~= y:
hitAreas.append(.leftBelow)
fallthrough
default:
break
}
return hitAreas
}
しかし実行してみると、見事にwhere句の条件も無視されていました。
print(checkHitAreas(x: 0, y: 0).map { $0.rawValue }) // 期待: [右上, 左下] -> 実際: [右上, 左下]
print(checkHitAreas(x: 6, y: 6).map { $0.rawValue }) // 期待: [右上] -> 実際: [右上, 左下]
print(checkHitAreas(x: -6, y: -6).map { $0.rawValue }) // 期待: [左下] -> 実際: [右上, 左下]
fallthroughはcaseの指定だけでなくwhereの条件も全て無視するんですね
わざわざwhereが書いてると、直感的には判定に使ってくれそうな気がしていて勘違いしていました
正しいコード
今回のように排他的ではない条件で判定をしたい場合は、素直にif文で書く他ないようです
func checkHitAreas(x: Int, y: Int) -> [AreaType] {
var hitAreas: [AreaType] = []
if -5...10 ~= x && -5...10 ~= y {
hitAreas.append(.rightAbove)
}
if -10...5 ~= x && -10...5 ~= y {
hitAreas.append(.leftBelow)
}
return hitAreas
}
print(checkHitAreas(x: 0, y: 0).map { $0.rawValue }) // [右上, 左下]
print(checkHitAreas(x: 6, y: 6).map { $0.rawValue }) // [右上]
print(checkHitAreas(x: -6, y: -6).map { $0.rawValue }) // [左下]