//先执行 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 中说明
因此,如果我们想在
guard
或 if
语句中的可选绑定(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 }
}
然而,这两者并不完全相同。
guard
语句,以防初始条件子句变成 false
(然后不进行可选绑定(bind),而是直接进入 else
语句的 guard
块) 在某些情况下,我们自然会更喜欢一种而不是另一种,例如如果条件子句包含一些非常繁重的计算,我们可能不想执行这些,除非我们确定可选绑定(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/