Swift 2引入了guard关键字,它可以用来确保各种数据配置就绪。我在这个网站上看到的一个例子演示了一个submitTapped函数:
func submitTapped() {
guard username.text.characters.count > 0 else {
return
}
print("All good")
}
我想知道使用guard与使用if条件的老式方法是否有任何不同。它是否提供了简单支票无法获得的好处?
Swift 2引入了guard关键字,它可以用来确保各种数据配置就绪。我在这个网站上看到的一个例子演示了一个submitTapped函数:
func submitTapped() {
guard username.text.characters.count > 0 else {
return
}
print("All good")
}
我想知道使用guard与使用if条件的老式方法是否有任何不同。它是否提供了简单支票无法获得的好处?
当前回答
警卫的陈述就要做了。这是两个不同的问题
1)它允许我减少嵌套的if语句 2)它是增加我的范围,我的变量可访问
if语句
func doTatal(num1 : Int?, num2: Int?) {
// nested if statement
if let fistNum = num1 where num1 > 0 {
if let lastNum = num2 where num2 < 50 {
let total = fistNum + lastNum
}
}
// don't allow me to access out of the scope
//total = fistNum + lastNum
}
保安声明
func doTatal(num1 : Int?, num2: Int?) {
//reduce nested if statement and check positive way not negative way
guard let fistNum = num1 where num1 > 0 else{
return
}
guard let lastNum = num2 where num2 < 50 else {
return
}
// increase my scope which my variable accessible
let total = fistNum + lastNum
}
其他回答
这确实有两大好处需要保护。一个是避免厄运金字塔,就像其他人提到的那样——许多恼人的if语句嵌套在彼此之间,越来越向右移动。
另一个好处是你想要实现的逻辑通常是“if not let”而不是“if let {} else”。
这里有一个例子:假设你想要实现accumulate -一个map和reduce之间的交叉,它会返回一个运行的reduce数组。下面是guard:
extension Sliceable where SubSlice.Generator.Element == Generator.Element {
func accumulate(combine: (Generator.Element,Generator.Element)->Generator.Element) -> [Generator.Element] {
// if there are no elements, I just want to bail out and
// return an empty array
guard var running = self.first else { return [] }
// running will now be an unwrapped non-optional
var result = [running]
// dropFirst is safe because the collection
// must have at least one element at this point
for x in dropFirst(self) {
running = combine(running, x)
result.append(running)
}
return result
}
}
let a = [1,2,3].accumulate(+) // [1,3,6]
let b = [Int]().accumulate(+) // []
你怎么写它没有守卫,但仍然使用第一,返回一个可选?就像这样:
extension Sliceable where SubSlice.Generator.Element == Generator.Element {
func accumulate(combine: (Generator.Element,Generator.Element)->Generator.Element) -> [Generator.Element] {
if var running = self.first {
var result = [running]
for x in dropFirst(self) {
running = combine(running, x)
result.append(running)
}
return result
}
else {
return []
}
}
}
额外的嵌套是恼人的,而且,if和else相隔太远也不符合逻辑。让空case提前退出,然后继续函数的其余部分,就好像这是不可能的一样,可读性要高得多。
简单地说,它提供了一种在执行之前验证字段的方法。这是一种很好的编程风格,因为它增强了可读性。在其他语言中,它可能是这样的:
func doSomething() {
if something == nil {
// return, break, throw error, etc.
}
...
}
但是因为Swift为你提供了可选项,我们不能检查它是否为nil并将其值赋值给一个变量。相反,if let检查它不是nil,并分配一个变量来保存实际值。这就是警卫发挥作用的地方。它为您提供了一种更简洁的方式,可以使用可选项提前退出。
用保护我们的意图是明确的。如果这个特定条件不满足,我们就不想执行其余的代码。 在这里我们也可以扩展链,请看看下面的代码:
guard let value1 = number1, let value2 = number2 else { return }
// do stuff here
一个好处是消除了大量嵌套的if let语句。请在15:30左右观看WWDC“Swift新功能”视频,其中一节名为“末日金字塔”。
何时使用警卫
如果你有一个带有一些UITextField元素或一些其他类型的用户输入的视图控制器,你会立即注意到你必须展开textField。文本可选,以获得内部的文本(如果有!)。isEmpty在这里不会有任何好处,没有任何输入,文本字段将简单地返回nil。
因此,你有一些这样的东西,你将它们展开并最终传递给一个函数,该函数将它们发布到服务器端点。我们不希望服务器代码必须处理nil值或错误地向服务器发送无效值,因此我们将首先使用guard打开这些输入值。
func submit() {
guard let name = nameField.text else {
show("No name to submit")
return
}
guard let address = addressField.text else {
show("No address to submit")
return
}
guard let phone = phoneField.text else {
show("No phone to submit")
return
}
sendToServer(name, address: address, phone: phone)
}
func sendToServer(name: String, address: String, phone: String) {
...
}
您会注意到,我们的服务器通信函数以非可选的String值作为参数,因此会提前展开保护。展开有点不直观,因为我们习惯使用if let来展开,它将值展开以在块中使用。这里guard语句有一个相关联的块,但它实际上是一个else块——也就是说,如果展开失败,你所做的事情——值被直接展开到与语句本身相同的上下文中。
//关注点分离
没有保护
如果不使用guard,我们最终会得到一大堆类似于末日金字塔的代码。这不能很好地扩展向表单添加新字段或使代码非常可读。缩进可能很难遵循,特别是在每个分支上有这么多其他语句。
func nonguardSubmit() {
if let name = nameField.text {
if let address = addressField.text {
if let phone = phoneField.text {
sendToServer(name, address: address, phone: phone)
} else {
show("no phone to submit")
}
} else {
show("no address to submit")
}
} else {
show("no name to submit")
}
}
是的,我们甚至可以将所有这些语句合并为一个用逗号分隔的语句,但我们将失去找出哪条语句失败并向用户显示消息的能力。
https://thatthinginswift.com/guard-statement-swift/