Update
在 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)
}
}
你运气不好,因为你不能使用可选链。
tl; dr
您更喜欢一件很酷的单线吗?
doStuff <^> optA <*> optB
继续阅读。虽然它看起来有多么可怕,但它确实很强大,而且使用起来并不像看起来那么疯狂。
幸运的是,使用函数式编程方法可以轻松解决这个问题。您可以使用Applicative
抽象并提供apply
将多个选项组合在一起的方法。
这是一个例子,取自http://robots.thoughtbot.com/function-swift-for-dealing-with-optional-values http://robots.thoughtbot.com/functional-swift-for-dealing-with-optional-values
首先,我们需要一个函数,仅当可选值包含某些内容时才将函数应用于可选值
// this function is usually called fmap, and it's represented by a <$> operator
// in many functional languages, but <$> is not allowed by swift syntax, so we'll
// use <^> instead
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(+) <^> optA <*> optC // Some 3