【Swift】安全にアンラップするために 〜!（強制アンラップ）とif letとguard letと??（Nil coalescing operator）の使い分け〜

## 1. はじめに
この記事は[レコチョク Advent Calendar 2021](https://qiita.com/advent-calendar/2021/recochoku)の21日目の記事となります。

株式会社レコチョクで、iOSアプリの開発をしている新卒1年目の後藤です。
米津玄師・スキマスイッチ・BUMP OF CHICKENのみなさんに、日々活力を頂いております。

Swiftにはオプショナル型という`nil`を許容した型があります。これを非オプショナル型の値として取り出すためには、アンラップという作業が必要です。

この記事では

- !（強制アンラップ）
- if let
- guard let
- ??（Nil coalescing operator）

を使ってどのようにアンラップするか、どう使い分けるかを中心にまとめます。


## 2. オプショナル型とは
Swiftでは通常のデータ型（Int型やString型など）には、`nil`を代入することができません。
そこで、オプショナル型を使うと変数に`nil`を代入することができるようになります。

```swift
var hoge: String? // オプショナル型の宣言
var fuga: String // 非オプショナル型の宣言

hoge = nil // ok（オプショナル型なので、nilが代入できる）
fuga = nil // コンパイルエラー（非オプショナル型なので、nilが代入できない）
```

## 3. !での強制アンラップ

オプショナル型の変数の値を、非オプショナル型の値として取り出す（上記の例でいうと`hoge`の`String?`型を`String`型にする）ためには、アンラップという作業が必要です。

`変数名!`と書くと、強制的にアンラップすることができます。しかし、アンラップした変数が`nil`であった場合、実行時エラーが発生してしまいます。

```swift
var hoge: String? // オプショナル型の宣言
print(hoge!) // 実行時エラー（hogeがnilのため強制アンラップに失敗し、実行時にエラーが発生）
```

そのため、オプショナル型の変数が`nil`でないことが保証できる場合のみ使用しましょう。

## 4. オプショナルバインディング（if let・guard let）でのアンラップ

上記の例のように`変数名!`でアンラップすると、`nil`であった場合、実行時エラーが発生してしまいます。

そこで、安全にアンラップする方法の一つとして、オプショナルバインディングがあります。オプショナルバインディングを使うことで、`nil`であるかを確認して処理を進めることができます。

オプショナルバインディングは、2つの構文が存在します。

- if let
- guard let

### if let
if let文は、オプショナル型変数に`nil`が含まれているかどうかによって、後続の処理を分岐させることができます。

```swift
let hoge: String? = nil // hogeの中身はnil
if let _hoge = hoge { 
    // hogeがnilではなかった時の後続処理… 
} else {
    // hogeがnilだった時の後続処理… 
}
```

### guard let
guard let文は、オプショナル型変数に`nil`が含まれている場合、その時点で処理を中断させることができます。

下記のコードでは`hoge`が`nil`のため、else節で`return`され、早期リターンします。また、if let文と比べて、後続の処理（コード）のネストを浅くすることができ、コードが読みやすくなります。

なお、guard let文は、関数の中でしか実行することができないため注意が必要です。

```swift
let hoge: String? = nil // hogeの中身はnil

guard let _hoge = hoge else { return } // hogeはnilなのでreturnされる
// hogeがnilではなかった時の後続処理… 
// if letと比べて後続処理がネストの中に入らないため、ネストを浅くすることができる
```

### 両方に共通すること

if let文も guard let文も、条件を`nil`以外にも指定することができます。例えば下記の例だと、`hoge`が`nil`ではないかつ、`A`という値を持っていたらprint文が実行されます。

```swift
let hoge: String? = "A"
if let _hoge = hoge, _hoge == "A" {
    print("hogeはnilではない かつ Aという文字列が入っています")
}
```

また、複数の変数を同時に、`nil`が入っているのかを確認することもできます。

```swift
var a: Int? = 10 // オプショナル型（nilを許容する）
var b: Int? = 20 // オプショナル型（nilを許容する）

if let a = a, let b = b {
    // aとbが両方ともnilではなかった時の後続処理…
    print(a + b) // 30
} else {
    // aとbのどちらか一方でもnilだった時の後続処理… 
    print("failed")
}
```

```swift
func add(_ a: Int?, _ b: Int?) {
    guard 
        let a = a,
        let b = b
    else {
        return // returnを忘れるとコンパイルエラー
    }
    // a,bともにnilではなかった時の後続処理… 
    // if letと比べて後続処理がネストの中に入らないため、ネストを浅くすることができる
    print(a + b)
}

var a: Int? = 10 // オプショナル型（nilを許容する）
var b: Int? = 20 // オプショナル型（nilを許容する）
add(a, b) // 30
```

## 5. ??（Nil coalescing operator）でのアンラップ

Nil coalescing operatorでも、オプショナル型の変数が`nil`なのかを確かめることができます。

```swift
変数 = オプショナル型変数 ?? (nilの場合の値)
```
Nil coalescing operatorは`nil`だった場合、予め用意しておいた値を代入します。そのため、先ほど紹介したif let文やguard let文とは異なり`nil`だったときの処理を条件分岐させて書くことができません。

Nil coalescing operatorは、`nil`だったときのデフォルト値が想定されている場合で使用すると良いです。例えば下記の例では、楽曲アプリを作成していてタイトルやアーティストの情報が取得できなかったら、予め用意しておいたデフォルト値を入れています。

```swift
var title: String?
var artist: String?

titleLabel.text = title ?? "不明なタイトル"
artistLabel.text = artist ?? "不明なアーティスト"
```

## 6. まとめ
本記事では、オプショナル型の変数に格納された値を取り出す（アンラップする）ための方法として、4通りの方法を紹介しました。

- !（強制アンラップ）
    - `nil`の場合で、実行時エラーが発生してしまう
    - `nil`でないことが保証できる場合のみ使用する
- if let
    - `nil`の場合で、行いたい処理がある場合に使用する
- guard let
    - `nil`の場合で、それ以上処理を進めたくない場合に使用する（早期リターンできる）
    - 関数の中でしか使うことができない
- ?? （Nil coalescing operator）
    - `nil`の場合で、デフォルト値を設定できる場合に使用する
    - `nil`の場合で、条件分岐をさせることができない

最後まで読んでいただき、ありがとうございました。

明日の[レコチョク Advent Calendar 2021](https://qiita.com/advent-calendar/2021/recochoku)は22日目「MediaElement.jsでメディアプレイヤーのUIをサクッとつくる」となります！お楽しみに。

## 参考記事
[【初心者向け】Swiftの"?"と"!"，はじめからていねいに (1/2)](https://techblog.recochoku.jp/7513)

[【初心者向け】Swiftの"?"と"!"，はじめからていねいに (2/2)](https://techblog.recochoku.jp/7519)

[2.1.12. オプショナル | 基本 | Swift](http://www.studiogalago.com/the-swift-programming-language/language-guide/the-basics/optionals/)

[guard letとif letの使い分け](https://qiita.com/solty_919/items/8b22c8b30cd1a5596c83)

[【Swift】guard文、guard let文の使い方/ if letとの違いも](https://note.com/iga34engineer/n/n293547a644e3)

[Swiftでif let文を使って出来ることとguard letの使い分けに関して](https://arma-search.jp/article/swift-if-let)

[新卒iOSエンジニアがコードレビューを受けて気づいたポイント4選](https://qiita.com/yayamochi/items/8470b767872414fb634b)

---
この記事はレコチョクのエンジニアブログの記事を転載したものとなります。

https://techblog.recochoku.jp/8058