Swift: guard
vs if
, and guard let
vs if let
(English)
この質問を guard
対 if
と、 guard let
対if let
で分けたほうが分かりやすくなると思います。
guard
対if
ただのguard
とif
はどちらも単純なフロー制御ステートメントであり、アンラップは行いません。
guard
は、その条件が満たされない場合、ただ早期に終了します。
比較表
guard |
if |
|
---|---|---|
機能性 | 早期に終了 | フロー制御 |
焦点 | 早期に終了の道: 先に進む前に、条件の正しさを確認すること。 | ハッピーパス:すべてが計画どおりに進んだときの機能の動作。 |
読みやすさ、明瞭さ | 改善 | **pyramid of doom(死のピラミッド)**につながる可能性があります |
入れ子にされたスコープ (深度を増加) | ❌ | ◯ |
外側のスコープ | 必要 | 不必要 |
必要 | チェックが失敗した場合はスコープから戻ります | |
Return / Throw | 必要 | 不必要 |
役割 | バリデーション | ただのフロー制御 |
適切な場所 | スコープの開始場所 |
例
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))
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ステートメントの後のスコープでアクセスできます:
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(死のピラミッド)」のはコンピュタープログラミングでフロー制御するためにネストされたインデントの多くのレベルを使用することです。
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()
}
}