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条件的老式方法是否有任何不同。它是否提供了简单支票无法获得的好处?
当前回答
当使用守护满足条件时,它将在守护块中声明的变量暴露给代码块的其余部分,将它们带入其作用域。如前所述,这将在嵌套的if let语句中派上用场。
注意,guard在其else语句中要求return或throw。
使用Guard解析JSON
下面是一个如何使用guard而不是if-let解析JSON对象的示例。这是一篇博客文章的节选,其中包括一个playground文件,你可以在这里找到:
如何使用守卫在Swift 2解析JSON
func parseJSONWithGuard(data : [String : AnyObject]) throws -> Developer {
guard let firstname = data["First"] as? String else {
return Developer() // we could return a nil Developer()
}
guard let lastname = data["Last"] as? String else {
throw ParseError.BadName // or we could throw a custom exception and handle the error
}
guard let website = data["WebSite"] as? String else {
throw ParseError.BadName
}
guard let iosDev = data["iosDeveloper"] as? Bool else {
throw ParseError.BadName
}
return Developer(first: firstname, last: lastname, site: website, ios: iosDev)
}
下载操场:守卫操场
更多信息:
以下是Swift编程语言指南的节选:
If the guard statement’s condition is met, code execution continues after the guard statement’s closing brace. Any variables or constants that were assigned values using an optional binding as part of the condition are available for the rest of the code block that the guard statement appears in. If that condition is not met, the code inside the else branch is executed. That branch must transfer control to exit the code block that that guard statement appears in. It can do this with a control transfer statement such as return, break, or continue, or it can call a function or method that doesn’t return, such as fatalError().
其他回答
和if语句一样,guard也根据表达式的布尔值执行语句。与if语句不同,guard语句只在条件不满足时运行。您可以将守卫更像Assert,但是可以优雅地退出,而不是崩溃。
请参考: http://ericcerney.com/swift-guard-statement/
它确实使具有多个查找和可选项的序列流更加简洁和清晰,并减少了大量if嵌套。参见Erica Sadun关于替换if的帖子. ....可能会忘乎所以,下面是一个例子:
let filteredLinks = locationsLinkedToList.filter({$0.actionVerb == movementCommand})
guard let foundLink = filteredLinks.first else {return ("<Person> cannot go in that direction.", nil, nil)}
guard filteredLinks.count == 1 else {return ("<Person> cannot decide which route to take.", nil, nil)}
guard let nextLocation = foundLink.toLocation else {return ("<Person> cannot go in that direction.", nil, nil)}
看看能不能坚持下去。
与if不同,guard创建的变量可以从其块外访问。打开大量的可选项是有用的。
这确实有两大好处需要保护。一个是避免厄运金字塔,就像其他人提到的那样——许多恼人的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提前退出,然后继续函数的其余部分,就好像这是不可能的一样,可读性要高得多。
用保护我们的意图是明确的。如果这个特定条件不满足,我们就不想执行其余的代码。 在这里我们也可以扩展链,请看看下面的代码:
guard let value1 = number1, let value2 = number2 else { return }
// do stuff here