斯威夫特:守卫vs如果让

lmi*_*asf 105 conventions optional control-flow swift swift2

我一直在阅读关于Swift中的Optionals,我已经看过if let用于检查Optional是否包含值的示例,以及它是否存在 - 使用unwrapped值执行某些操作.

但是,我已经看到在Swift 2.0中,关键字guard主要用于.我想知道是否if let已从Swift 2.0中删除或是否仍然可以使用它.

我应该改变我的计划包含if letguard

Rob*_*ier 143

if letguard let提供类似但不同的目的.

"else"的情况guard必须退出当前范围.通常这意味着它必须调用return或中止程序.guard用于提供早期返回,而不需要嵌套其余的功能.

if let嵌套其范围,并不需要任何特殊的东西.它可以return或不.

一般来说,如果if-let块将是函数的其余部分,或者它的else子句中有一个return或中止,那么你应该使用它guard.这通常意味着(至少在我的经验中),如果有疑问,guard通常是更好的答案.但是有很多情况if let仍然适合.

  • 当`non-nil`情况有效时,使用`if let`.当`nil`表示某种错误时,请使用`guard`. (19认同)
  • @BallpointBen我不同意这一点.在很多情况下,即使没有错误,`guard`也是合适的.有时它只意味着无所事事.例如,如果let title = title else {return}`,`positionTitle`方法可能会"保护".标题可以是可选的,在这种情况下,这不是错误.但是"守卫让"仍然是合适的. (4认同)
  • 换句话说,当代码 99% 确定不使用 else 条件时,使用“guard let”;另一方面,当代码为 50 - 50(示例)时使用“if let”以使用 else 条件。 (3认同)
  • 由“if let”绑定的变量仅在“if let”范围内**可见。由“guard let”绑定的变量随后可见。因此,使用防护来绑定可选值也是有意义的。 (2认同)

Hon*_*ney 88

警卫可以提高清晰度

当您使用守护你有很多的后卫预期成功,它是比较重要的,如果它不成功,那么你只是想退出范围的早期.就像你守卫看文件/图像是否存在,如果数组是否为空.

func icon() -> UIImage {
    guard let image = UIImage(named: "Photo") else {
        return UIImage(named: "Default")! //This is your fallback
    }
    return image //-----------------you're always expecting/hoping this to happen
}
Run Code Online (Sandbox Code Playgroud)

如果用if-let编写上面的代码,它会向读取开发人员传达它更多的50-50.但是,如果你使用防护,你会增加代码的清晰度,这意味着我希望它能在95%的时间内工作......如果它失败了,我不知道为什么会这样; 这是非常不可能......但是只需使用这个默认图像,或者只是用一个有意义的消息断言来描述出错的地方!

  • guard当它们产生副作用时避免使用,防护装置要用作自然流动.从else条款引入副作用时避免使用防护装置.警卫为代码正确执行建立了必要条件,提供早期退出

  • 当您在正分支中执行重要计算时,重构ifguard语句并返回else子句中 的回退值

来自: Erica Sadun的Swift Style书

此外,由于上述建议和干净的代码,您更可能希望/需要将断言添加到失败的保护语句中,它只是提高了可读性,并使其他开发人员清楚地了解您的期望.

guard? ?let? image = ?UIImage?(named: selectedImageName) else { // YESSSSSS
     assertionFailure(?"Missing ??\(?selectedImageName?)?? asset"?) 
     return
} 

guard? ?let? image = ?UIImage?(named: selectedImageName) else { // NOOOOOOO
?     ?return 
}
Run Code Online (Sandbox Code Playgroud)

来自: Erica Sadun的Swift Style书 +一些修改

(你不会对if-lets 使用断言/前置条件.它似乎不正确)

使用警卫还可以避免厄运的金字塔,从而帮助您提高清晰度.见Nitin的答案.


Guard创建一个变量

我认为没有人能够很好地解释一个重要的区别.

双方guard letif let 解开但是变量

随着guard let创建一个将存在else语句之外的新变量.

随着if let没有创建任何新的可变后else语句,只需输入代码块,如果选购的是非零.新创建的变量只存在于代码块内部而不是之后!

guard let:

func someFunc(blog: String?) {

    guard let blogName = blog else {
        print("some ErrorMessage")
        print(blogName) // will create an error Because blogName isn't defined yet
        return
    }
    print(blogName) // You can access it here ie AFTER the guard statement!!

    //And if I decided to do 'another' guard let with the same name ie 'blogName' then I would create an error!
    guard let blogName = blog else { // errorLine: Definition Conflicts with previous value.
        print(" Some errorMessage")
        return
    }
    print(blogName)
}
Run Code Online (Sandbox Code Playgroud)

if-let:

func someFunc(blog: String?) {


    if let blogName1 = blog {
        print(blogName1) // You can only access it inside the code block. Outside code block it doesn't exist!
    }
    if let blogName1 = blog { // No Error at this line! Because blogName only exists inside the code block ie {}
        print(blogName1)
    }
}
Run Code Online (Sandbox Code Playgroud)

有关详细信息,if let请参阅:为什么重新声明可选绑定不会产生错误


Guard需要范围退出

(在Rob Napier的回答中也提到过):

你必须 func中guard定义.它的主要目的是中止/返回/退出范围,如果条件不满足:

var str : String?

guard let blogName1 = str else {
    print("some error")
    return // Error: Return invalid outside of a func
}
print (blogName1)
Run Code Online (Sandbox Code Playgroud)

因为if let你不需要在任何func中包含它:

var str : String?    
if let blogName1 = str {
   print(blogName1) // You don't get any errors!
}
Run Code Online (Sandbox Code Playgroud)


div*_*gio 45

何时使用if-let以及何时使用guard往往是一种风格问题.

假设您有func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int一个可选的项目数组(var optionalArray: [SomeType]?),0如果数组是nil(未设置)或者count数组是否有值(设置),则需要返回.

您可以使用if-let以下方式实现它:

func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int
    {
        if let array = optionalArray {
            return array.count
        }
        return 0
    }
Run Code Online (Sandbox Code Playgroud)

或者像这样使用guard:

func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int
    {
        guard let array = optionalArray else {
            return 0
        }
        return array.count
    }
Run Code Online (Sandbox Code Playgroud)

这些例子在功能上是相同的.

guard当你有一个像验证数据这样的任务时,真正发光的地方,如果出现任何问题,你希望函数提前失败.

if-let当你接近完成验证时,"成功路径"和现在成功绑定的选项都在方法的主要范围内,而不是嵌套一堆s,因为失败路径已经全部返回.


Nit*_*bur 28

我将尝试用一些(未经优化的)代码来解释保护语句的有用性.

您有一个UI,您可以使用名字,姓氏,电子邮件,电话和密码验证用户注册的文本字段.

如果任何textField不包含有效文本,则应将该字段设为firstResponder.

这是未经优化的代码:

//pyramid of doom

func validateFieldsAndContinueRegistration() {
    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{
                    // all text fields have valid text
                    let accountModel = AccountModel()
                    accountModel.firstName = firstNameString
                    accountModel.lastName = lastNameString
                    accountModel.email = emailString
                    accountModel.password = passwordString
                    APIHandler.sharedInstance.registerUser(accountModel)
                } else {
                    password.becomeFirstResponder()
                }
            } else {
                email.becomeFirstResponder()
            }
        } else {
            lastName.becomeFirstResponder()
        }
    } else {
        firstName.becomeFirstResponder()
    }
}
Run Code Online (Sandbox Code Playgroud)

您可以在上面看到,所有字符串(firstNameString,lastNameString等)只能在if语句的范围内访问.所以它创造了这个"厄运金字塔"并且有许多问题,包括可读性和易于移动的东西(如果字段的顺序被改变,你必须重写大部分代码)

使用guard语句(在下面的代码中){},如果所有字段都有效,您可以看到这些字符串在外部可用并且可以使用.

// guard let no pyramid of doom
func validateFieldsAndContinueRegistration() {

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
        }

// all text fields have valid text
    let accountModel = AccountModel()
    accountModel.firstName = firstNameString
    accountModel.lastName = lastNameString
    accountModel.email = emailString
    accountModel.password = passwordString
    APIHandler.sharedInstance.registerUser(accountModel)
}
Run Code Online (Sandbox Code Playgroud)

如果字段的顺序发生变化,只需向上或向下移动相应的代码行,就可以了.

这是一个非常简单的解释和用例.希望这可以帮助!

  • 我知道我不应该在这里说谢谢,但是谢谢。这真的帮助我了解了守卫! (3认同)

Kir*_*n K 10

基本差异

警卫让

  1. 从范围早期存在的过程
  2. 要求得分如回归,投掷等.
  3. 创建一个可以访问范围的新变量.

如果让

  1. 无法访问范围.
  2. 无需退回声明.但我们可以写

注意:两者都用于解包Optional变量.


wil*_*aks 7

我看到的最清晰的解释是在Github Swift Style Guide中:

if增加了一个深度:

if n.isNumber {
    // Use n here
} else {
    return
}
Run Code Online (Sandbox Code Playgroud)

guard没有:

guard n.isNumber else {
    return
}
// Use n here
Run Code Online (Sandbox Code Playgroud)


小智 7

Guard let 与 if let 的比较

func anyValue(_ value:String?) -> String {
    
    guard let string = value else {
        return ""
    }
    
    return string
}

func anyValue(_ value:String?) -> String {
    
    if let string = value {
        return string
    }
    
    return ""
}
Run Code Online (Sandbox Code Playgroud)

  • 这个简单的例子最好不使用“if let”或“guard let”来编写。就写`返回值?? ”“`。 (3认同)

Aks*_*hay 5

警卫

\n\n
\n
    \n
  • Aguard将程序控制转移到范围之外。\n\xe2\x80\x99t。

  • \n
  • 语句中任何条件的值guard必须是 \n 类型Bool或桥接到的类型Bool。该条件也可以是可选的绑定声明。

  • \n
\n
\n\n

保护语句具有以下形式:

\n\n
guard condition else {\n    //Generally return\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

如果让

\n\n
\n \n
\n\n
if let roomCount = optionalValue {\n    print("roomCount available")\n} else {\n    print("roomCount is nil")\n}\n
Run Code Online (Sandbox Code Playgroud)\n