LoginSignup
1
2

More than 3 years have passed since last update.

【Swift】タプルを用いたswitch文

Posted at

1.はじめに


今回はSwitch文の条件分岐にタプルの値を使う、通常とは少し違った使い方を紹介しようと思います。場面によっては有効な使い方だと思うので、ぜひご覧ください。

2.タプルをcaseで使う


まず、タプルを定数のように考えてcaseラベルに置くようにすれば、次のように書くことができます。
ただし、タプルの型はすべて統一されている必要があり、この例では、変数dayが月と日からなる日付を表すタプルを持っていると考えます。
3つだけ書かれているいずれかの祝日に一致すれば表示されます。

switch day {
case (1,1): print("元旦")
case (2,11): print("建国記念の日")
case (5,3): print("憲法記念日")
default: break
}

ある範囲の日付を表すために、範囲演算子が使えます。例えば次の例を確認してください。

switch day {
case (1,1...5): // 1/1 ~ 1/5
    print("正月休み")

case (5,3): print("憲法記念日")

case (4,29), (5,2...6):
    print("連休")

default: break
}

値を列挙するだけでなく、タプルの要素を取り出して処理に使うこともできます。
このために、caseラベル内にlet、またはvarを記述して、case節の内部でだけ有効な定数、変数を宣言できます。

switch day {
case (5,3): print("憲法記念日")
case (8, let d): print("8/\(d)は夏休みです")
default: break
}

この例では、8月の日付ならいつでも夏休みになります。変数dを使う必要がなければ、「_」を使い次のように記述することもできます。

case (8, _): print("夏休み")

なお、キーワード付きのタプルをswitch文で使用することもできますが、値とcaseラベルで使っているキーワードが一致しない場合にはエラーになります。
タプルとcaseのラベルの対応付けのように、構造と値の一致を調べる処理一般を、Swiftではパターンマッチングといいます。

3.switch文でwhere節を使う


switch文で、タプルの要素に対して条件を付けることもできます。ここで、日付から曜日を計算する関数dayOfWeekを利用します。この関数は日曜なら0、月曜なら1、というように曜日を整数値で返します。なお、変数yearが西暦年を持つとします。
caseラベルに条件を付ける場合、ラベルと「:」の間に、予約語whereと条件を記述します。以下の例を確認してください。

switch day {
case (1, let d) where d >= 8 && d <= 14 && dayOfWeek(year,1,d) == 1:
    print("成人の日")

case (8, _): print("夏休み")

case (let m, let d) where dayOfWeek(year,m,d) == 0:
    print("\(m)/\(d)は日曜日")

default: break
}

ここでは、1月の第2月曜日が成人の日であることを条件にしています。
同様に、1年のいつでも日曜日であれば表示するようにしています。
このcaseラベルのように、タプルのすべての要素を定数に割り当てる場合、要素ごとにletを指定することもできますが、タプルの前に1つだけletを記述することもできます。

case let (m, d) where dayOfWeek(year,m,d) == 0:
    print("\(m)/\(d)は日曜日")

なお、caseラベルでletやvar、whereを使って条件を指定する方法は、タプルだけでなく、通常の整数などに対しても利用できます。

定数や変数を使うラベルは、別並べると「,」で区切って並べる際に制約があります。
これは、どのラベルの条件に一致したかによって、定数や変数が値を持たない可能性があるからです。
例えば以下のようにすることはできません。

switch t {
case (1, let y), (2, 2):
    print("\(y)")

case (2, _):
    fallthrough

case (let z, 2):
    print("\(z)")
default: break
}

caseラベルで定数や変数を使っているcase節へは、すぐ上の選択肢からfallthrough文で遷移することはできません。

ラベルを「,」で区切って並べた時、それらが定数や変数を含んでよい条件は、すべてのラベルが同じ名前、同じ型の定数もしくは変数を含むことです。
つまり、どんな場合でも定数もしくは変数の値が定まる必要があります。その点だけ気を付けてください。

4.オプショナル型をswitch文で使う


switch文で場合分けしたい式がオプショナル型の値を含む場合も、caseのラベルで書き分けることができます。
例として名前と年齢からなるタプル型を考えます。ただし、年齢は不明の場合があるのでオプショナル型になっています。

typealias People = (String, Int?)

このような型をSwitch文で扱うには、caseパターンで「?」という記号を使います。

switch m {
case let (name, age?) where age >= 18:
    print("\(name), 免許取得可")

case let (name, (15...18)?):
    print("\(name), 高校生")

case (let name, nil):
    print("\(name), 年齢不明")

default: break
}

このように、対応する定数もしくは変数に「?」を付けると、オプショナル型がnil以外の値を持つときにマッチし、その後のwhere節や実行分では開示演算子を使うことなく値を参照できます。
また、nilを記述しておけば、オプショナル型がnilの値を持つ場合にマッチします。範囲を示すパターンは()で囲みます。

オプショナルであることを示す「?」は、タプルなどの他のパターンに利用することができます。
例えばPepole?型の変数opsをswitch文で使うとすれば、caseには次のように記述できます。

switch ops {            // opsはPeople?型
case let (name, 18?)? : // 開示した結果が(文字列, 18)ならマッチする

5.おわりに


今回はタプルを用いたswitch文の利用法について書きました。次回は列挙型についての記事を書こうと思っているので、よろしければぜひご覧ください。
ここまで見てくださった方、ありがとうございました。

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