斯威夫特:后卫VS如果让

我一直在阅读关于Swift中的Optionals,并且我看到了一些例子, if let用来检查一个Optional是否包含一个值,并且是这样的话 – 用一个解包的值做一些事情。

不过,我已经看到,在Swift 2.0中,主要使用关键字guard 。 我想知道是否已经从Swift 2.0中删除了,还是可以使用。

我是否应该改变我的程序, if letguard

if letguard let服务类似,但截然不同的目的。

guard的“其他”情况必须退出当前范围。 通常这意味着它必须调用return或中止程序。 guard是用来提供早期的回报,而不需要嵌套其余的function。

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

一般来说,如果if-let块将成为函数的其余部分,或者else子句将会return或中止,那么您应该使用guard 。 这通常意味着(至less以我的经验),如果有疑问, guard通常是更好的答案。 但是, if let还是合适的if let还有很多情况。

守卫可以提高清晰度

当你使用后卫时,你有更高的期望值让后卫获得成功 ,而如果失败成功则有点重要,那么你只是想尽早退出。 就像你看看是否存在一个文件/图像,如果一个数组是空的或不。

 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 } 

如果你用if来写上面的代码,让它传达给阅读开发者,它是50-50的更多。 但是如果你使用守卫,那么你的代码就更加清晰了,这意味着我希望95%的时间能够工作……如果失败了,我不知道为什么会这样; 这是不太可能的…但是,然后只是使用这个默认的图像,或者也许只是用一个有意义的消息断言什么错了!

  • 当他们创造副作用时避免guard ,警卫被用作自然stream动当避免其他条款引入副作用时避免警卫。 警卫build立必要的条件,以正确执行代码, 提前退出

  • 在正分支中执行重要计算时,从if重构为guard语句并在else子句中返回fallback值

来自: Erica Sadun的Swift Style书

同样由于上述build议和干净的代码,它更有可能需要/需要将断言添加到失败的守卫语句,它只是提高了可读性,并使其他开发人员清楚你所期待的。

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

来自: Erica Sadun的Swift Style书

(你不会使用if-let的assert / preconditions,这看起来不正确)

使用警卫还可以帮助你通过避免死亡金字塔来提高清晰度。 见Nitin的答案 。


Guard创build一个新的variables

有一个重要的区别,我相信没有人解释得很好。

然而, if let 解包variables的话

有了guard正在创build一个新的variables,将存在else语句之外。 你正在创build一个variables。

if let没有创build任何新的variables,在else语句之后, 如果可选项非零,则只能input代码块。 新创build的variables只存在于代码块内部 ,不在!

guard:

 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) } 

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) } } 

有关if let我们看看更多信息: 为什么重新声明可选绑定不会产生错误


守卫需要范围退出

(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) 

因为if let你不需要任何func:

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

什么时候使用if-let和何时使用guard通常是一个风格问题。

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

你可以像这样使用if-let来实现它:

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

或者像这样使用guard

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

这些例子在function上是相同的。

guard真正闪耀的是当你有任务像validation数据,并且你希望如果有什么错误的function提前失败。

当您接近完成validation时,不是嵌套一堆if-let s,而是“成功path”和现在成功绑定的option都在方法的主要范围内,因为失败path已经全部返回。

我将尝试用一些(未优化的)代码来解释guard语句的用处。

此代码正在validation视图上的文本字段,以便用户注册名字,姓氏,电子邮件,电话和密码。

如果任何textField不包含有效的文本,它应该使该字段firstResponder。

 //if let 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() } } 

你可以在上面看到,所有的string(firstNameString,lastNameString等)只能在if语句的范围内访问。

有了guard语句(在下面的代码中),你可以看到这些string是可用的,如果所有的字段都是有效的,就可以使用。

 // 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) } 

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

  Basic Difference Guard let 1. Early exist process from the scope 2. Require score existing like return, Throw etc. 3. Create a new variable those can be access out the scope. if let 1. Can not access out the scope. 2. no need to return statement. But we can write NOTE: Both are used to unwrapped the Optional variable. 

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

if添加一个深度级别:

 if n.isNumber { // Use n here } else { return } 

guard不:

 guard n.isNumber else { return } // Use n here