更新
在Swift 1.2中,您可以执行以下操作:
if let a = optA, let b = optB {
doStuff(a, b)
}
原始回答
在你的特定情况下,你可以使用可选链:
if let b = optionaObj?.a?.b {
// do stuff
}
现在,如果您需要做的是:
if let a = optA {
if let b = optB {
doStuff(a, b)
}
}
你没那么幸运,因为你无法使用可选链。
简短易懂版
你想要一句简洁的表达吗?
doStuff <^> optA <*> optB
请继续阅读。尽管看起来很可怕,但这实际上是非常强大的,并且使用起来并不像看起来那么疯狂。
幸运的是,这是一个可以轻松解决的问题,只需使用函数式编程方法即可。 您可以使用 Applicative 抽象,并提供一个apply
方法来组合多个选项。
这里有一个例子,摘自http://robots.thoughtbot.com/functional-swift-for-dealing-with-optional-values
首先,我们需要一个函数,仅当可选值包含某些内容时才将函数应用于可选值
infix operator <^> { associativity left }
func <^><A, B>(f: A -> B, a: A?) -> B? {
switch a {
case .Some(let x): return f(x)
case .None: return .None
}
}
然后我们可以使用 apply 将多个选项组合在一起,我们将其称为 <*>
,因为我们很酷(而且我们懂一些 Haskell)
// <*> is the commonly-accepted symbol for apply
infix operator <*> { associativity left }
func <*><A, B>(f: (A -> B)?, a: A?) -> B? {
switch f {
case .Some(let value): return value <^> a
case .None: return .None
}
}
现在我们可以重新编写我们的例子。
doStuff <^> optA <*> optB
只要doStuff
是柯里化形式的(见下文),这将起作用,即:
func doStuff(a: A)(b: B) -> C { ... }
整个事情的结果是一个可选值,可以是nil
,也可以是doStuff
的结果。以下是在playground中尝试的完整示例:
func sum(a: Int)(b: Int) -> Int { return a + b }
let optA: Int? = 1
let optB: Int? = nil
let optC: Int? = 2
sum <^> optA <*> optB // nil
sum <^> optA <*> optC // Some 3
作为最后的说明,将函数转换为其柯里化形式非常简单。例如,如果您有一个接受两个参数的函数:
func curry<A, B, C>(f: (A, B) -> C) -> A -> B -> C {
return { a in { b in f(a,b) } }
}
现在您可以使用柯里化(curry)任何两个参数的函数,比如说+
curry(+) <^> optA <*> optC // Some 3
if let
块,但我不太喜欢它。 - Craig Otis