Swift：guard　対　if　と、guard let　対　if let

#Swift: `guard` vs `if`, and `guard let` vs `if let` ([English](https://qiita.com/loic-meister-guild/items/ba2bccda7bf109f9bd57))
この質問を `guard`対` if`と、 `guard let`対`if let`で分けたほうが分かりやすくなると思います。
## `guard`対`if`
ただの`guard`と`if`はどちらも単純なフロー制御ステートメントであり、アンラップは行いません。

`guard`は、その条件が満たされない場合、ただ早期に終了します。
### 比較表
|| `guard` | `if` |
|:---:|:---:|:---:|
| 機能性 | 早期に終了 | フロー制御 |
| 焦点 | **早期に終了の道**： 先に進む前に、条件の正しさを確認すること。 | **ハッピーパス**：すべてが計画どおりに進んだときの機能の動作。 |
| 読みやすさ、明瞭さ | **改善** | **pyramid of doom(死のピラミッド)**につながる可能性があります |
| 入れ子にされたスコープ　（深度を増加） | ❌ | ◯ |
| 外側のスコープ | 必要 | 不必要 |
| 必要 | チェックが失敗した場合はスコープから戻ります | |
| Return / Throw | 必要 | 不必要 |
| 役割 | バリデーション | ただのフロー制御 |
| 適切な場所 | スコープの開始場所 |  |
### 例
```code:guard
let array = ["a", "b", "c"]
func at(at index: Int) -> String?{
   // インデックスが範囲外の場合は早期に終了
   guard index >= 0, index < array.count  else { return nil }
   return array[index]
}
print(at(1))
```
```code:if
let array = ["a", "b", "c"]
let index = 1
if index >= 0, index < array.count {
    print(array[index])
} else {
    print(nil)
}
```
## `guard let`対`if let`
`guard let`と`if let`は両方ともOptional型をアンラップします。

`guard let`は、`guard`と同様に、条件が満たされない場合、早期に終了します。
### 比較表
|| `guard let` | `if let` |
|:---:|:---:|:---:|
| 機能 | Optional型をアンラップ | Optional型をアンラップ |
| 設計目標 | チェックが失敗した場合は、現在のスコープを終了します | ただOptional型をアンラップ |
| 焦点 | **早終了の道**： 先に進む前に、条件の正しさを確認すること。 | **ハッピーパス**：すべてが計画どおりに進んだときの機能の動作。 |
| 外側のスコープ | 必要 | 不必要 |
| 必要 | チェックが失敗した場合はスコープから戻ります | |
| Return / Throw | 必要 | 不必要 |
| 読みやすさ、明瞭さ | **改善** | **pyramid of doom(死のピラミッド)**につながる可能性があります |
| 入れ子にされたスコープ　（深度を増加） | ❌ | ◯ |
| 可視性 | ラップされていないOptional型は、`guard let`ステートメントの**後**のスコープに**可視**できます | ラップされていないOptional型は、`if let`ステートメントのコードブロックスコープで**のみ可視**できます |
| 役割 | いくつかのOptional型をバリデーションしてからアンラップします. | ただのフロー制御 |
| 適切な場所 | スコープの開始場所 |  |
| 複数のOptional型を同時にアンラップ | 可能 | 可能 |
| 副作用 | 避けるべき | 大丈夫 |
### 例
##### `guard let`
すべてのフィールドが有効な場合、すべての文字列（firstNameString、lastNameString、emailString、passwordString）は、guardステートメントの後のスコープでアクセスできます：

```code:guard-let
func validateThenRegisterUser() {
    // validation
    guard let firstNameString = firstName.text where firstNameString.characters.count > 0 else {
            firstName.becomeFirstResponder()
            return
        }
    guard let lastNameString = lastName.text where lastNameString.characters.count > 0 else {
            lastName.becomeFirstResponder()
            return
        }
    guard let emailString = email.text where 
        emailString.characters.count > 3 &&
        emailString.containsString("@") && 
        emailString.containsString(".") else {
            email.becomeFirstResponder()
            return
        }
    guard let passwordString = password.text where passwordString.characters.count > 7 else {
            password.becomeFirstResponder()
            return
        }

    // The validated information can now be used for registration
    let newUser = User()
    newUser.firstName = firstNameString
    newUser.lastName = lastNameString
    newUser.email = emailString
    newUser.password = passwordString
    APIHandler.sharedInstance.registerUser(newUser)
}
```
##### `if let`
すべての文字列（firstNameString、lastNameString、emailString、passwordString）は、`if`ステートメントコードブロックのスコープ内でのみアクセスできます。

これにより、次のような多くの問題が発生する「pyramid of doom(死のピラミッド)」が作成されます:

- 読みやすさ,
- コードの並べ替え/リファクタリングのしやすさ。たとえば、フィールドのバリデーション順序が変更された場合、ほとんどのコードを書き直す必要があります。

※ 「pyramid of doom(死のピラミッド)」のはコンピュタープログラミングでフロー制御するためにネストされたインデントの多くのレベルを使用することです。

```code:if-let
func validateThenRegisterUser() {
    // validation: starts the pyramid of doom
    if let firstNameString = firstName.text where firstNameString.characters.count > 0{
        if let lastNameString = lastName.text where lastNameString.characters.count > 0{
            if let emailString = email.text where emailString.characters.count > 3 && emailString.containsString("@") && emailString.containsString(".") {
                if let passwordString = password.text where passwordString.characters.count > 7{
                    // The validated information can now be used for registration
                    let newUser = User()
                    newUser.firstName = firstNameString
                    newUser.lastName = lastNameString
                    newUser.email = emailString
                    newUser.password = passwordString
                    APIHandler.sharedInstance.registerUser(newUser)
                } else {
                    password.becomeFirstResponder()
                }
            } else {
                email.becomeFirstResponder()
            }
        } else {
            lastName.becomeFirstResponder()
        }
    } else {
        firstName.becomeFirstResponder()
    }
}
```