如果它位于顶层,我可以按预期调用flatMap
:
func id<T>(v: T) -> T {
return v
}
var foo: Int?
foo.flatMap(id) // returns nil
foo = 1
foo.flatMap(id) // returns 1
但是,当我尝试使用flatMap
来实现我只能想象它的强烈目的(在这种情况下组成多个Optionals)时,编译器会抛出错误:
var bar: Int?
foo.flatMap { $0 + bar.flatMap(id) }
// error: value of optional type 'Int?' not unwrapped; did you mean to use '!' or '?'?
// foo.flatMap { $0 + bar.flatMap(id) }
// ^
为什么我在前两个示例中没有打开可选内部的可选项?这有点挫败了flatMap
的目的吗?
答案 0 :(得分:2)
您无法添加可选项和数字
var v1 : Int?
let sum = v1 + 2 //Will throw a compilation error
这是一个编译错误,因为v1
可能是零。将{2}添加到nil
在您的示例foo.flatMap { $0 + bar.flatMap(id) }
bar.flatMap(id)
会返回一个可选的
foo.flatMap { $0 + (bar.flatMap(id) ?? 0)}
答案 1 :(得分:2)
您似乎认为flatMap
返回未包装的值。它没有。是的,它确实尝试解包原始值,如果此解包成功则调用closure(并返回闭包返回的任何内容),但如果原始值无法解包则返回nil
。正如the documentation所说:
当此
Optional
实例不是nil
时,评估给定的闭包,将未包装的值作为参数传递。...
返回:给定闭包的结果。如果此实例为
nil
,则返回nil
。
正如您所看到的,flatMap
的结果因此是可选的,例如如果你看一下flatMap
声明:
func flatMap<U>(_ transform: (Wrapped) throws -> U?) rethrows -> U?
所以,让我们回过头看看你的第一个代码片段。你说:
var foo: Int? foo = 1 foo.flatMap(id) // returns 1
没有。它返回Int?
,即此示例中的Optional(1)
。它不会返回1
。
那么请考虑一下:
var bar: Int?
let result = foo.flatMap { $0 + bar.flatMap(id) }
由于bar.flatMap(id)
将返回Int?
,编译器会抱怨您正在尝试添加$0
(foo
的展开值,假设它可以解包它)使用Optional<Int>
,导致错误,因为它询问您是否打算从此表达式的后半部分解包该值。
为了说清楚,请考虑这个例子:
let result = foo.flatMap { value -> Int? in
// calculate some result using `value`, which is `foo` unwrapped,
// and return it; if `foo` couldn't be unwrapped, this closure is
// not called and `result` is `nil`
return calculatedValue
}
这是一个很好的功能,相当于以下内容:
let result: Int?
if let value = foo {
// calculate result from `value`, which is `foo` unwrapped
// and update `result` accordingly
result = calculatedValue
} else {
// otherwise just set `result` to `nil`
result = nil
}
答案 2 :(得分:1)
与map()
不同,flatMap()
确实剥离了可选性,但其主要目的是为了展平&#34;展平&#34;一个多维数组。
使用闭包将一个数组中的项映射到另一个数组中,然后加入结果。选项和数组都是&#34;容器&#34;并且flatMap()
删除了一级遏制。
在您的示例中,您尝试将一个未包装的可选项添加到可选项中,但这不起作用。
如果要对可选整数数组求和,可以尝试这个例子。
let foo: Int?
let bar: Int?
let myArray = [foo, bar]
let sum = myArray.flatMap().reduce(0, +)
这将返回整数的总和,如果它们都是零,则返回零。
答案 3 :(得分:0)
foo.flatMap(id)
不返回 1。它返回 Optional(1)
。
foo.flatMap { $0 + bar.flatMap(id) }
中断,因为 foo.flatMap
可以被解包,因此它执行闭包。但是 bar.flatMap(id)
不能被评估为非可选(见我的第一点)。
flatMap
在此上下文中与此代码的作用相同:
var optionalInt = Int("5A")
if let unwrappedInt = optionalInt {
optionalInt = unwrappedInt + 5
}
注意我们必须如何使用 if let
来解包才能使用 +
运算符?
flatMap
的一个用途是它为我们提供了便利,无需解开即可使用 +
。如果表达式评估为 nil
,则不会执行。但整个事情返回一个可选的。像这样:
let result = optionalInt.flatMap { 5 + $0 }
此处 result
的计算结果为 nil