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条件的老式方法是否有任何不同。它是否提供了简单支票无法获得的好处?
当前回答
阅读这篇文章,我注意到使用Guard的巨大好处
下面你可以用一个例子来比较guard的用法:
这是没有防备的部分:
func fooBinding(x: Int?) {
if let x = x where x > 0 {
// Do stuff with x
x.description
}
// Value requirements not met, do something
}
在这里,您将所需的代码放在所有条件中 您可能不会立即发现这有什么问题,但是您可以想象,如果它嵌套了许多在运行语句之前都需要满足的条件,那么它会变得多么令人困惑
解决这个问题的方法是首先进行每一项检查,如果有任何不符合就退出。这样可以很容易地理解什么条件将使该函数退出。
但是现在我们可以使用guard,我们可以看到它可以解决一些问题:
func fooGuard(x: Int?) {
guard let x = x where x > 0 else {
// Value requirements not met, do something
return
}
// Do stuff with x
x.description
}
检查你想要的条件,而不是你不想要的条件。这同样类似于断言。如果条件不满足, 运行Guard的else语句,跳出函数。 如果条件通过,这里的可选变量将自动在保护的范围内为您展开 语句被调用——在本例中是fooGuard(_:)函数。 您可以尽早检查坏的情况,使您的函数更易于阅读和维护
同样的模式也适用于非可选值:
func fooNonOptionalGood(x: Int) {
guard x > 0 else {
// Value requirements not met, do something
return
}
// Do stuff with x
}
func fooNonOptionalBad(x: Int) {
if x <= 0 {
// Value requirements not met, do something
return
}
// Do stuff with x
}
如果你还有任何问题,你可以阅读整篇文章:Swift guard声明。
结束
最后,通过阅读和测试,我发现如果你使用guard来打开任何可选选项,
这些未包装的值将保留在您的其余部分中使用 代码块
.
guard let unwrappedName = userName else {
return
}
print("Your username is \(unwrappedName)")
在这里,打开的值只在if块中可用
if let unwrappedName = userName {
print("Your username is \(unwrappedName)")
} else {
return
}
// this won't work – unwrappedName doesn't exist here!
print("Your username is \(unwrappedName)")
其他回答
与if不同,guard创建的变量可以从其块外访问。打开大量的可选项是有用的。
它确实使具有多个查找和可选项的序列流更加简洁和清晰,并减少了大量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 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语句嵌套在彼此之间,越来越向右移动。
另一个好处是你想要实现的逻辑通常是“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提前退出,然后继续函数的其余部分,就好像这是不可能的一样,可读性要高得多。