1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

fallthroughはwhere条件を無視するので非排他的条件には使えなさそう

Posted at

概要

Swiftのswitch文では、通常caseまたはdefaultを1つしか通りません。
しかし以降のcaseも続けて実行したい場合には、 fallthroughを使うことで実現することが可能です :checkered_flag:
これは 判定値が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文で当たり判定の算出を試みました :triangular_ruler:
例として、2つの領域 rightAboveleftBelow を定義し、その中にPが含まれている場合にその情報を配列で返したいとします。

image.png

座標が領域に含まれることをチェックする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の条件も全て無視するんですね :warning:
わざわざwhereが書いてると、直感的には判定に使ってくれそうな気がしていて勘違いしていました :droplet:

正しいコード

image.png

今回のように排他的ではない条件で判定をしたい場合は、素直にif文で書く他ないようです :relieved:

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 }) // [左下]

参考リンク

1
1
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
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?