【Swift】オプショナル型のアンラップ! (??、!、guard、guard let、if let の使い方)

## オプショナル型とは？
- 値が存在するか、しないか分からない時に使用される型です
- `nil`が含まれる可能性のある場合に使用します

### 使い方
- 型名の後ろに`?`をつけることで`nil`を代入することができる
- アンラップを行うには`??`、`!`、`guard`、`guard let`, `if let`などを使用します

``` Swift: How to use Optional
let hoge: Int? = nil
var name: String? = "高橋"
```

## オプショナル型をアンラップしましょう
- 例えば次のコードの場合、`nil`が含まれている可能性のあるので、コンパイルエラーとなってしまいます

``` Swift
let num: Int? = nil
let num2: Int? = 0

print(num + num2)
// Binary operator '+' cannot be applied to two 'Int?' operands
```

## `??`とは?
- 「nil結合演算子」と呼ばれる
- オプショナル型の変数・定数に値が含まれている場合はその値を返し、nilの場合はデフォルト値を返す演算子

### 構文
- デフォルト値には`hoge`が`nil`だった場合、`unwrappedHoge`に代入する値を書く

``` Swift: nil coalescing operator Sample
let hoge: Int? = 10
let unwrappedHoge = hoge ?? /* デフォルト値 */
```

### 使い方
- `num`が`nil`の場合は`0`が代入されるコード

``` Swift: How to use nil coalescing operator
let num: Int? = 10
let unwrappedName = num ?? 0
```

## `!`とは?
- 「強制アンラップ」と呼ばれ、値が存在する、しないに関係なくアンラップを行う
- オプショナル型変数が`nil`の場合、強制アンラップを使用すると**アプリがクラッシュ**します
- 関係なしにアンラップを行うので**使うことをおすすめしません**

### 使い方
- オプショナル型の定数`name`を強制アンラップし、出力するコード
- アンラップしたい定数名の後ろに`!`をつける

``` Swift
let name: String? = "高橋"
print(name!)
// 出力: 高橋

let hoge: String? = nil
print(hoge!) // `nil`を強制アンラップしたのでクラッシュ!
```

## `guard`とは?
- 条件を満たさない場合に処理を早期に終了させる構文です

### 構文
- 条件式が`false`になる場合 `{}` 内のコードが実行されます

```Swift: guard Sample
guard /* 条件式 */ else {
    // 関数を抜けるコード
    // 例: `return`や`throw`
}
```

### 使い方
- 引数で受け取った`name`の値が「hoge」の場合は早期リターンするコード

``` Swift: How to use guard
func guardSample(name: String) -> String {
    // `name`が「hoge」の場合は早期リターン
    guard name != "hoge" else {
        return "早期リターン"
    }
    
    return "名前は\(name)です!"
}

// nameが「hoge」の場合
print(guardSample(name: "hoge"))
// 出力: 早期リターン

// nameが「高橋」の場合
print(guardSample(name: "高橋"))
// 出力: 名前は高橋です!
```

## `guard let`とは？
- Swiftで値が存在することを確認するための構文です
- **オプショナル型の値を安全にアンラップできる!!!**

### 構文
- 見た目は`guard`とほとんど同じです
- 右辺値が`nil`の場合に`{}`内のコードを実行します
``` Swift: guard let Sample
guard let /* 定数名 */ = /* オプショナル型の変数・定数 */ else {
    // 関数を抜けるコード
    // 例: `return`や`throw`
}

// guard letでアンラップされた定数(/* 定数名 */)が使用できる
```

### 使い方
- 引数で受け取ったnameが`nil`の場合、早期リターンを行うコード

``` Swift: How to use guard let
func guardLetSample(name: String?) -> String {
    // 引数nameが`nil`の場合は早期リターン
    guard let unwrappedName = name else {
        return "早期リターン"
    }
    
    // アンラップされた定数`unwrappedName`が使用できる
    return "名前は\(unwrappedName)です!"
}

// nameが`nil`の場合
print(guardLetSample(name: nil))
// 出力: 早期リターン

// nameが「高橋」の場合
print(guardSample(name: "高橋"))
// 出力: 名前は高橋です!
```
> Swift5.7より以下のように省略して書くことができるようになりました
> 
> ``` Swift
> func guardLetSample(name: String?) -> String {
>     // `guard let name = name`を省略した形
>     guard let name else {
>         return "早期リターン"
>     }
>     
>     // アンラップされた定数`name`が使用できる
>     return "名前は\(name)です!"
> }
> ```

## `if let`とは？
- 右辺値に値が入っているかどうかで条件分岐処理を行うことができる構文
- **オプショナル型の値を安全にアンラップできる!!!**

### 構文
- 見た目は`if`と似ています
``` Swift: if let Sample
if let /* 定数名 */ = /* オプショナル型の変数・定数 */ {
    // 右辺値が存在した場合
    // このブロック内で/* 定数名 */を使用することができる
} else {
    // 右辺値が`nil`だった場合
    // /* 定数名 */を使用することはできない!!!
}
```

### 使い方
- 引数`name`に値が存在するかどうかで分岐処理を行うコード 
``` Swift: How to use if let
func ifLetSample(name: String?) -> String {
    if let unwrappedName = name {
        // 引数nameに値が存在した場合
        // unwrappedNameが使用可能
        return "名前は\(unwrappedName)です!"
    } else {
        return "nameはnilでした!"
    }
}

// nameが`nil`の場合
print(ifLetSample(name: nil))
// 出力: nameはnilでした!

// nameが「高橋」の場合
print(ifLetSample(name: "高橋"))
// 出力: 名前は高橋です!
```

> `guard let`と同様に省略した書き方ができます
> ``` Swift
> func ifLetSample(name: String?) -> String {
>     // `if let name = name {}`を省略した形
>     if let name {
>         // nameと引数のnameは別物
>         // このブロック内のnameはアンラップされたname
>         return "名前は\(name)です!"
>     } else {
>         return "nameはnilでした!"
>     }
> }
> ```

## 最後に
最後までご覧いただきありがとうございます🙏
意見等ありましたらコメントいただけると幸いです
分からないことだらけなので、勉強の参考にさせてください😢