# 条件式

Swiftの条件分岐は、if文、switch文、guard文などがあります。

# if文

条件式が true を返す場合、{} の処理を実行し、false の場合は実行されません。

let a = 1
let b = 1

if a == b {
  print("実行されました")
}

// print("実行されました")

# else節

if文にelse節を使うと、条件が一致しなかったときの処理を実行することができます。

let a = 1
let b = 1

if a != b {
  print("実行されました")
} else {
  print("else節が実行されました")
}

// print("else節が実行されました")

# if let文

if let文は、Optional Binding で使用することができます。

Optional型の値を取り出すことができれば、{} の処理を実行し、値がnilのときは処理を実行しません。

let a: Int? = 10

if let b = a {
  print(b) // 10
}

また、同様にelse節も使用できます。

var a: Int?

if let b = a {
  print(b)
} else {
  print("値はありませんでした")
}

// 値はありませんでした

if let文は、複数のOptional型の値を取り出すことができます。

let a: Int? = 10
let b: String? = "Hello"

if let c = a, let d = b {
  print(c)    // 10
  print(d)    // Hello
}

どちらかに値が無かった場合は、if文内の処理は実行されません。


 










let a: Int? = 10
var b: String?

if let c = a, let d = b {
  print(c)
  print(d)
} else {
  print("どちらかに値がありませんでした")
}

// どちらかに値がありませんでした

# if let文とas?演算子

if let文で、as? 演算子を使用すると、型をダウンキャストすることができます。

let a: Any = "Any String"

if let b = a as? String {
  print(b) // Any String
}

TIP

ダウンキャストとは、同じクラス階層において、汎用的な型から、より具体的な型へ変換させることをいいます。この場合、Any型という汎用的な型から、より具体的なString型へ変換させています。

as? 演算子の詳しい使い方は、型キャスト の章をご確認ください。

# switch文

switch文は複数の条件式に応じて処理を実行するときに使うことができます。

switch文は上から順番に条件式を評価して、条件にマッチしたら処理を実行し、終了します。

let a = 10

switch a {
case 1..<10:
  print("1から9の値です")
case 10...100:
  print("10から100の値です")
default:
  print("それ以外の値です")
}

// 10から100の値です

# 様々な型を指定

Swiftでは、switch文に様々な型を指定することができます。

# Double型の指定

let a = 1.9

switch a {
case 0.0..<1.0:
  print("0.0から1.0の値です")
case 1.0...2.0:
  print("1.0から2.0の値です")
default:
  print("それ以外の値です")
}

// 1.0から2.0の値です

# enum型の指定

enum Animal {
  case Dog, Cat, Rabbit
}

let someAnimal = Animal.Dog

switch someAnimal {
case .Dog:
  print("🐶")
case .Cat:
  print("🐱")
case .Rabbit:
  print("🐰")
}

// "🐶"

enum型を指定する時は、定義されているenumのケースを全て網羅するように注意してください。

enumのケースが足りない時は、コンパイラはエラーを出力します。

enum Animal {
  case Dog, Cat, Rabbit
}

let someAnimal = Animal.Dog

switch someAnimal {
case .Dog:
  print("🐶")
case .Cat:
  print("🐱")
}

// Rabbitがないのでエラーになる

// error: switch must be exhaustive
// switch someAnimal {
// ^
// main.swift:7:1: note: add missing case: '.Rabbit'
// switch someAnimal {

Swiftのswitch文は基本的にdefaultは必須ですが、enumのときは全てのケースを満たしていれば書く必要はありません。しかし、ケースを満たしていない状態でdefault文を書くと、その分のケースを代わりに満たしたとコンパイラは解釈します。

enum Animal {
  case Dog, Cat, Rabbit
}

let someAnimal = Animal.Dog

switch someAnimal {
case .Dog:
  print("🐶")
case .Cat:
  print("🐱")
default:
  print("それ以外")
}

// 🐶

これはあくまで動作の説明ですので列挙型の場合はケースを明示的に書くのがいいでしょう。

# where

whereは、ケースにマッチする条件式を追加することができます。

let a: Int? = 100

switch a {
case let b? where b > 10:
  print("10より大きいです")
case let b? where b < 10:
  print("10より小さいです")
default:
  print("値が存在しません")
}

// 10より大きいです

case let b? は、 case Optional.some(let b) のシンタックスシュガーです。case内でアンラップして値を取り出しています。値があれば、where句以降の条件式を評価し、マッチする場合は処理を実行しています。

値がない場合は、defaultの処理が実行されます。

let a: Int? = nil

switch a {
case let b? where b > 10:
  print("10より大きいです")
case let b? where b < 10:
  print("10より小さいです")
default:
  print("値が存在しません")
}

// 値が存在しません

Tuple型を使うと、次のように書くことができます。

let score = (100, 90)

switch score {
case (let a, let b) where a > b:
  print("aはbより大きいです")
default:
  print("aはbより小さいです")
}

// aはbより大きいです

score.0let a に代入され、 score.1let b に代入されます。そのあとにwhere句の条件式が評価され、条件がマッチすれば処理が実行されます。

# break

break文を使うと、処理を中断することができます。

let a: Int = 1

switch a {
case 0...10:
  print("ここは実行されます")

  break

  print("ここは実行されません")
default:
  break
}

// ここは実行されます

# fallthrough

fallthroughは、ケースを途中で終了させ、次のケースを実行することができます。

let a: Int = 1

switch a {
case 0...10:
  print("ここは実行されます")

  fallthrough

  print("ここは実行されません")
default:
  print("defaultは実行されます")
}

// ここは実行されます
// defaultは実行されます

最初のケースを実行後に、一度中断して、そのあとにdefaultのケースを実行しています。

# guard文

guard文は条件が一致しなかったときだけ、{} 内の処理を実行します。

{} の中では、最後にreturnなどをして処理を抜ける必要があります。


 
 
 








func test(_ int: Int) {
  guard int > 10 else { 
    return
  }


  print(int)
}

test(100) // 100
test(1)   // (出力なし)

guard文は一般的に次のような使い方をします。

# 特定の条件で処理を終了させたい場合

例えば、値が10以上の時だけ処理を実行させたいケースを考えてみましょう。

if文で書いた場合はこのようになります。

func doSomething(_ int: Int) {
  if int >= 10 {
    // 処理を実行
  }
}

doSomething(20)

さらに、そのif文の中で条件を追加してみます。

func doSomething(_ int: Int) {
  if int >= 10 {
    let a = int - 5

    if a > 5 {
      let b = a - 1

      if b > 3 {
        // 処理を実行
      }
    }
  }
}

doSomething(20)  // 14

条件が増えるごとに、if文がネストしています。例文は単純な処理しかしていませんが、実際の開発だともっと複雑な条件になる可能性があります。

上記の例をguardを使って書いてみましょう。

func doSomething(_ int: Int) {
  // 10以下のときは処理を終了
  guard int >= 10 else { return }

  let a = int - 5

  // 5より小さいときは処理を終了
  guard a > 5 else { return }

  let b = a - 1

  print(b)
}

doSomething(20)  // 14

guard文を使ったことにより、if文のネストがなくなりました。また、コードがシンプルになり可読性が上がりました。

if文のネストが多くなったときは、guard文を使ってコードを簡潔にできるか検討してみましょう。

TIP

if文やswitch文などの条件が増えることで、循環的複雑度 は高くなります。 一般的に、循環的複雑度が低い方が処理が簡潔になり可読性が良いとされています。

# 変数をアンラップして以降の処理で使いたい場合

if文と同様に、guard文もletと組み合わせて変数をアンラップすることできます。

アンラップした値はguard文以降のスコープで使用することができます。

func doSomething(_ int: Int?) {
  guard let a = int else { return }

  // guard文以降も変数aを使うことができる
  print(a)
}

let num: Int? = 20
doSomething(num) // 20

let num2: Int? = nil
doSomething(num2) // (出力なし)

guard文でアンラップすることで、条件が満たされなかった時は処理が終了します。そのため、そのあとの変数の存在を保証することができます。