警卫声明不一致

时间:2016-05-26 19:53:10

标签: swift swift2 guard-statement

//首先执行let后面的bool检查导致编译错误

   self.action = {  [weak self] in
      guard let `self` = self, data.isJSON() else { return }

//首先进行bool检查,然后让工作

  self.action = {  [weak self] in
     guard data.isJSON(), let `self` = self else { return }

上述两个陈述似乎与我相同。为什么它在第一种情况下不起作用?

1 个答案:

答案 0 :(得分:4)

将您的问题重新构建为最小,完整且可验证的示例

首先请注意,如果您的问题包含minimal, complete and verifiable example (mvce),最好是以当前形式出现,而不是:

  • 关闭列表无关紧要,只有这里令人困惑
  • 未知的self(......没有上下文)同样只会令人困惑,与此问题无关。

相反,你的问题可以按照以下方式构建:

func foo(bar: Int?) {
    // 1. why does this cause a compile time error?
    guard let baz = bar, true else { return }

    // 2. whereas this does not?
    guard true, let bax = bar else { return }
}

下面的答案将讨论这个mvce,而不是原始问题中模糊的例子。最后还要注意,guard / guard let语句并不完全相关(唯一)w.r.t.问题的核心,因为我们看到if / if let语句的相同行为。以下答案将使用guard语句。

现在,我们可以在上面的1.中赎回编译时错误吗?而且,这两个陈述真的相同吗?

上面函数guard中第一个foo(...)语句的编译时错误非常明显

  

布尔条件需要where 将其与变量绑定分开。

     

修复此问题:将,替换为where

Language Guide - The Basics - Optional Binding

中也说明了这一点
  

您可以在单个if语句中包含多个可选绑定   并使用where子句检查Boolean条件。如果可选绑定中的任何值为nilwhere子句   评估为false,考虑整个可选绑定   不成功。

因此,如果我们想在guardif语句中使用可选绑定后的条件子句,则需要使用where子句将condition-clause与前面的可选绑定分开。

func foo(bar: Int?) {
    // 1. ok, compiles
    guard let baz = bar where true else { return }

    /* 2. or, include a conditional-clause prior to the
          optional binding, but is this really equivalent..? */
    guard true, let bax = bar else { return }
}
然而,这两个并不是真正相同的;

  • 语句2.上面允许我们将guard语句短路,以防初始条件子句变为false(然后不进入可选绑定,而是直接进入else声明的guard
  • 而上面的1.允许反过来:只有在可选绑定成功时才检查条件子句。

有些情况下,我们更喜欢一种,例如另一种,例如如果条件子句包含一些非常繁重的计算,我们可能不想执行这些,除非我们确定可选绑定成功

let heavyStuff: () -> Bool = { print("foo"); /* ... */ return true }

func foo(bar: Int?) {
    /* 1. call the heavyStuff boolean construct only if
          the optional binding succeeds */
    guard let baz = bar where heavyStuff() else { return }

    /* 2. possibly unnesessarily perform heavy boolean
          stuff prior to failing the optional binding */
    guard heavyStuff(), let bax = bar else { return }
}

一个不那么人为的例子是,如果我们想在后面的条件子句中使用成功的绑定变量(这里:作为参数)

let integerStuff: (Int) -> Bool = { _ in /* ... */ return true }

func foo(bar: Int?) {
    /* 1. call the integerStuff boolean construct only if
          the optional binding succeeds, using the binded
          immutable as closure argument */
    guard let baz = bar where integerStuff(baz) else { return }

    /* 2. ... not really any good alternatives for such 
          flow if using this alternative */
    guard integerStuff(baz ?? 0), let bax = bar else { return }
}

最后请注意,技术上,如果您真的想要将初始可选绑定与以下条件子句分开,则可以使用虚拟case let(非可选的始终成功变量)绑定/赋值语句与条件子句

where关键字相结合
let checkThis: () -> Bool = { /* ... */ return true }

func foo(bar: Int?) {
    // ...
    guard let baz = bar, case let _ = () where checkThis() else { return }
}
然而,这只是为了表明这种技术性;在实践中,只需使用where子句。