//先执行 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 }

上面的两个陈述似乎对我来说是等价的。为什么它在第一种情况下不起作用?

最佳答案

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

首先请注意,如果您的问题包含 minimal, complete and verifiable example (mvce) 会更好,在目前的形式中,它不:

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

  • 相反,您的问题的 mvce 可以按照以下方式构建:
    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 中第 1 个 foo(...) 语句的编译时错误很能说明问题



    这也在 Language Guide - The Basics - Optional Binding 中说明



    因此,如果我们想在 guardif 语句中的可选绑定(bind)之后使用条件子句,则需要使用 where 子句将条件子句与前面的可选绑定(bind)分开。
    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(然后不进行可选绑定(bind),而是直接进入 else 语句的 guard 块)
  • 而上面的 1. 允许相反的情况:仅当可选绑定(bind)成功时才检查条件子句。

  • 在某些情况下,我们自然会更喜欢一种而不是另一种,例如如果条件子句包含一些非常繁重的计算,我们可能不想执行这些,除非我们确定可选绑定(bind)成功
    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 }
    }
    

    一个不那么做作的例子是,如果我们想在后面的条件子句中使用一个成功绑定(bind)的变量 in (here: as an argument)
    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 }
    }
    

    最后请注意,从技术上讲,如果您真的想将初始可选绑定(bind)与以下条件子句分开,您可以使用虚拟 case let(非可选的始终成功的变量绑定(bind)/赋值)语句以及 where 关键字作为您的条件-条款
    let checkThis: () -> Bool = { /* ... */ return true }
    
    func foo(bar: Int?) {
        // ...
        guard let baz = bar, case let _ = () where checkThis() else { return }
    }
    

    然而,这只是为了展示这种技术性;在实践中,只需使用 where 子句。

    关于swift - 守卫声明不一致,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/37469841/

    10-13 08:28
    查看更多