Swift的后卫关键字

Swift 2引入了guard关键字,可以用来确保各种数据已经configuration好了。 我在这个网站上看到的例子演示了一个submitTapped函数:

 func submitTapped() { guard username.text.characters.count > 0 else { return } print("All good") } 

我想知道,如果使用guard是不同于做旧的方式,使用if条件。 它是否提供了使用简单检查无法获得的好处?

阅读这篇文章,我注意到使用Guard的好处

在这里你可以比较一下使用守卫的一个例子:

这是没有防范的部分:

 func fooBinding(x: Int?) { if let x = x where x > 0 { // Do stuff with x x.description } // Value requirements not met, do something } 
  1. 在这里,您将所需的代码放入所有条件

    你可能不会马上看到这个问题,但是你可以想象,如果在运行你的语句之前嵌套了所有需要满足的条件,那么它会变得多么混乱

清理这个问题的方法是先完成每个检查,如果没有满足,就退出。 这允许容易理解什么样的条件将使这个function退出。

但现在我们可以使用警卫,我们可以看到有可能解决一些问题:

 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 } 
  1. 检查你想要的条件,而不是你不想要的条件。 这又是类似于断言。 如果条件不满足,则运行guard's else语句,这将突破function。
  2. 如果条件通过,这里的可选variables会在调用guard语句的范围内自动解包 – 在这种情况下,是fooGuard(_ :)函数。
  3. 您正在尽早检查不良案件,使您的function更易读,更易于维护

同样的模式也适用于非可选值:

 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 statement。

包起来

最后,阅读和testing我发现,如果你用警卫打开任何可选项,

那些未包装的值留在您的代码块的其余部分使用

 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创build了可以从块外部访问的variables。 拆开大量的Optional是很有用的。

guard真的有两大好处。 正如其他人所说的那样,人们正在避免厄运的金字塔 – if let彼此嵌套在一起的声明进一步向右移动的if let很多人会感到讨厌。

另一个好处是,你想实现的逻辑往往比“ if let { } else ”更“ if not let ”。

下面是一个例子:假设你想实现accumulate – 在mapreduce之间交叉,在这里它返回一个正在运行 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(+) // [] 

你会怎么写没有警惕,但仍然使用first返回一个可选的? 像这样的东西:

 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 [] } } } 

额外的嵌套是令人讨厌的,但是, ifelse分开,那就不合逻辑了。 让空的情况下尽早退出是更可读的,然后继续其余的function,就好像这是不可能的。

当使用guard进行条件满足时,会将在guard块内声明的variables暴露给代码块的其余部分,从而将它们引入其范围。 正如前面所说, if let放在一起,它肯定会派上用场。

请注意,守卫需要在其他语句中返回抛出

用GuardparsingJSON

下面是一个如何使用guard而不是if-letparsingJSON对象的例子。 这是一个博客条目的摘录,其中包括一个操场文件,你可以在这里find:

如何在Swift 2中使用Guard来parsingJSON

 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编程语言指南的摘录:

如果符合guard语句的条件,代码将在guard语句的大括号之后继续执行。 任何使用可选绑定作为条件一部分赋值的variables或常量都可用于guard语句出现的代码块的其余部分。

如果不满足该条件,则执行else分支中的代码。 该分支必须传递控制来退出该guard语句出现的代码块。它可以用一个控制传输语句(如return,break或continue)来完成,也可以调用一个不返回的函数或方法作为fatalError()。

一个好处是消除了很多嵌套的if let语句。 在15:30左右看到WWDC的“Swift的新变化”video,标题为“末日金字塔”。

使用警卫,我们的意图是明确的。 如果特定条件不满足,我们不想执行其余的代码。 这里我们也可以扩展链,请看下面的代码:

 guard let value1 = number1, let value2 = number2 else { return } // do stuff here 

什么时候使用警卫

如果你有一个带有几个UITextField元素或其他types的用户input的视图控制器,你会立即注意到,你必须解压textField.text可选,才能到达里面的文本(如果有!)。 isEmpty在这里没有任何好处,没有任何input,文本字段将简单地返回零。

所以你有一些你打开并最终传递给一个函数,将它们发布到服务器端点。 我们不希望服务器代码必须处理零值或错误地将无效值发送到服务器,所以我们将首先用警卫来解开这些input值。

 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值作为参数,因此警卫会事前解包。 解包是有点不直观的,因为我们习惯于解开,如果让一个块内部使用哪些解包值。 这里guard语句有一个关联的块,但是它实际上是一个else块 – 也就是说,如果解包失败,那么这个值直接parsing到与语句本身相同的上下文中。

// 关注点分离

没有警惕

没有使用警卫,我们最终将会得到一大堆类似于厄运金字塔的代码。 这不能很好地将新字段添加到我们的表单或使可读的代码。 缩进可能难以遵循,特别是在每个分支处有很多其他语句。

 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/

守卫声明要做。 它是不同的夫妇

1)允许我减less嵌套if语句
2)增加我的范围,我的variables可以访问

如果声明

 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 } 

从Apple文档:

警戒声明

如果没有满足一个或多个条件,则使用警戒语句将程序控制转移到范围之外。

Synatx:

 guard condition else { statements } 

优点:

通过使用guard语句,我们可以摆脱深层嵌套的条件,其唯一目的是validation一组要求。

它是专门为早期退出方法或function而devise的。

如果你使用如果让下面是代码看起来如何。

  let task = URLSession.shared.dataTask(with: request) { (data, response, error) in if error == nil { if let statusCode = (response as? HTTPURLResponse)?.statusCode, statusCode >= 200 && statusCode <= 299 { if let data = data { //Process Data Here. print("Data: \(data)") } else { print("No data was returned by the request!") } } else { print("Your request returned a status code other than 2XX!") } } else { print("Error Info: \(error.debugDescription)") } } task.resume() 

如果不满足一个或多个条件,使用保护可以将控制权转移出范围。

 let task = URLSession.shared.dataTask(with: request) { (data, response, error) in /* GUARD: was there an error? */ guard (error == nil) else { print("There was an error with your request: \(error)") return } /* GUARD: Did we get a successful 2XX response? */ guard let statusCode = (response as? HTTPURLResponse)?.statusCode, statusCode >= 200 && statusCode <= 299 else { print("Your request returned a status code other than 2XX!") return } /* GUARD: was there any data returned? */ guard let data = data else { print("No data was returned by the request!") return } //Process Data Here. print("Data: \(data)") } task.resume() 

参考:

1. 斯威夫特2:提前退出带有防守 2。 不祥之兆 3. 防守声明

它真的确实使序列的stream动具有多个查找和选项,更加简洁明了,并减less了大量的嵌套。 请参阅Erica Sadun的post以取代Ifs 。 ….可以拿走,下面的例子:

  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基于expression式的布尔值执行语句。 与if语句不同,guard语句只在条件不满足时才运行。 你可以把警卫想象成一个断言,而不是崩溃,你可以优雅地退出。

请参考: http : //ericcerney.com/swift-guard-statement/

简而言之,它提供了一种在执行之前validation字段的方法。 这是一个很好的编程风格,因为它提高了可读性。 在其他语言中,它可能看起来像这样:

 func doSomething() { if something == nil { // return, break, throw error, etc. } ... } 

但是因为Swift为你提供了可选项,所以我们不能检查它是否为零, 并把它的值赋给一个variables。 相反, if let检查它不是零,并分配一个variables来保存实际值。 这是guard进场的地方。 它给你一个更简洁的方式提前退出使用optionals。

Interesting Posts