swift小知识点之guard小结
一,guard 是一种控制流语句
与if语句相同的是,guard也是基于一个表达式的布尔值去判断一段代 码是否该被执行。与if语句不同的是,guard只有在条件不满足的时候才会执行这段代码。你可以把guard近似的看做是Assert,但是你可以优雅的退出而非崩溃。
guard是swift 2.0引入的,他有两个强大的理念optional unwrapping(可选绑定) 和 where clauses (where子句)。optional unwrapping 让我们避免金字塔式冗长的if语句。where clauses 附加了简单而强大的where表达式(Swift4后where被去掉了,直接使用,
相隔就行了),让我们可以非常方便审视正在验证的结果。
二,gaurd语句语法
guard expression else { //语句 //必须包含一个控制语句:return,break,continue或throw。 }
-
这里,expression是一个布尔表达式(返回true或者false)。
-
如果对表达式求值false,guard则执行代码块内的语句。
-
如果对表达式求值true,guard则从执行中跳过代码块内的语句
三,gaurd的简单使用
guard !name.isEmpty else { show("名字是空") return } doSomething()
-
从语法特点上来看,if满足条件要执行的代码放在前面的闭包内,不满足条件要执行的代码放在else的闭包内;guard不满足条件要执行的代码放在else的闭包内,满足条件要执行的代码放在guard语句的后面,不用放在guard的任何闭包中
-
guard有一个很大的特点,在else闭包中必须跟一个中断往后执行的关键字或者方法等,如return、continue、break、fatalError、throw等,这里有些同学有一个很大的误区,认为else闭包里只能用return
-
注意事项:
-
guard必须使用在函数内部;
-
guard必须带有else语句;
-
四,什么时候适合用guard
-
1、多个optional解包,并且需要都满足条件,比如做登录功能的时候
使用if做的两种方式:
-
方式1:
if let username = usernameTextField.text, !username.isEmpty { if let password = passwordTextField.text, !password.isEmpty { register(username, password) } else { show("密码不能为空") } } else { show("用户名不能为空") }
-
方式2:
if let username = usernameTextField.text, !username.isEmpty, let password = passwordTextField.text, !password.isEmpty { register(username, password) } else { show("用户名和密码不能为空") }
这两种方式的缺点:方式1中存在多重嵌套,如果不止用户名和密码,还有其他的,嵌套更深;方式2中if后面跟的语句过长,不方便阅读和理解,结构不清楚
使用guard怎么做:
guard let username = usernameTextField.text, !username.isEmpty else { show("用户名不能为空") return } guard let password = passwordTextField.text, !password.isEmpty else { show("密码不能为空") return } register(username, password)
使用guard结构清晰,方便阅读和理解,并且不造成嵌套
-
-
2、中断当前流程,当不满足条件时,不需要执行后面的逻辑,比如校验手机号码是否正确
-
使用if
func verifyMobilePhoneNumber(_ phoneNumber: String) -> Bool { if phoneNumber.isEmpty { return false } /// 检验逻辑。。。 }
-
使用guard
func verifyMobilePhoneNumber(_ phoneNumber: String) -> Bool { guard !phoneNumber.isEmpty { return false } /// 检验逻辑。。。 }
if、guard都能满足功能,但是guard的优势就在于,看到guard 中的条件,就知道不满足条件,就要中断当前流程,而使用if,还要去看if对应闭包的内容,才能判断是否中断流程,这里例子简单,看不出太多优势,当逻辑比较复杂后,guard在这里的优势就体现出来了
-
五,什么时候用if,而不能用guard
但是,并不意味着要将所有的 if … else … 和 if let … 都替换成 guard 语法。guard 语法很容易被滥用和误用,并不是所有的代码层次结构中都适合 guard 的使用。
- 作为 if 的相反情况时慎用
作为 if 的相反情况可以理解为作用域内的代码只有在传递进来的条件被判断为 false 的时候才执行.
例如当我们需要判断一个闭包参数表列中的 error 参数是否有返回值的时候,当 error 为 nil 时我们才有必要执行作用域内的代码,反之 return。这种情况下用 if 去实现就十分的清晰,可读性更高:
geoCoder.geocodeAddressString(textStr) { (placemarks : [CLPlacemark]?, error : NSError?) in // 为了编码的安全性考虑,我们对于必要的参数都要进行判断 // 如果有 error 那么就退出 if error != nil { print("error --- \(error)") return } // 如果有结果,那么看一下结果是否为空,为空退出 guard let placemarks = placemarks else { return } // 遍历所有的坐标(经纬度) for place in placemarks { print("wzywzywzy") } }
如果用 guard 去处理上面的 error,那么代码就变成了这样:
geoCoder.geocodeAddressString(textStr) { (placemarks : [CLPlacemark]?, error : NSError?) in // 如果 error 存在,那么执行作用域内的代码 guard let error = error else { // 如果有结果,那么看一下结果是否为空,为空退出 guard let placemarks = placemarks else { return } // 遍历所有的坐标(经纬度) for place in placemarks { print("wzywzywzy") } } // 作用域代码(存在 error,程序结束) print("error --- \(error)") return }
显然,用 guard 去处理上述情况就非常的不妥,造成了 guard 的大括号内还嵌套了一个 for 循环,可读性大大降低。
换句话说,如果你想让这个参数有值并使用它,那么就用 guard,如果你不想让这个参数有值那么就用 if 去判断。这样就可以将错误以及之后的 return 集中在一个大括号内,而顺利执行的作用域代码就在大括号外了。增强了代码的可读性。
- 不要在 guard 的 else 语句中放入复杂代码
guard 的 else 语句中,不应该放大量的代码,除了简单的提前退出的语句外。如果你在 guard 的 else 代码块中用了其他的代码逻辑或是实现了任何实际功能,那么你就误用了 guard 了。
总之,除一些简单提前退出的语句和一些离开了当前函数的必要操作外,不应该有其他的代码。
最好在 guard 的 else 语句块内不要多过 2 ~ 3 行代码。
- 不要用 guard 去代替一些比较复杂的 if else 语句
下面一段代码采用 if else 实现:
var str : String? = "Hello" if let helloStr = str where str!.hasPrefix("H") { print(helloStr) } else { print("不符合H开头要求") }
若采用 guard 去实现为:
var str : String? = "Hello" guard let helloStr2 = str where str!.hasPrefix("H") else { print("不符合H开头要求") return } print(helloStr2)
对于这种简单的情况而言,使用 if else 语句比起没有分支的 guard 语法更加容易理解。
六,总结
guard的优势在于,else闭包中必须使用中断当前流程的语句,并且满足条件要执行的代码不用放在guard的任何闭包中 使用guard能解决一些if嵌套问题和一些if代码不便于阅读理解和结构不清晰的问题