为什么 compactMap return 没有结果?

Why does compactMap return a nil result?

考虑这个代码片段:

var a: String? = "abc"
var b: String?

let result = [a, b].compactMap { [=11=] }

执行后result

["abc"]

这是预期的结果。这里result(ElementOfResult)的元素是String.

print(type(of: result))
Array<String>

现在到了有趣的部分。将片段更改为

var a: String? = "abc"
var b: Int?

let result = [a, b].compactMap { [=14=] }

并执行它,result将是

[Optional("abc"), nil]

这里result(ElementOfResult)的元素是Any,这是有道理的,因为AnyStringInt的公分母。

print(type(of: result))
Array<Any>

为什么 compactMap 返回的 nil 结果与其定义相矛盾?

来自苹果的 compactMap documentation

compactMap(_:)

Returns an array containing the non-nil results of calling the given transformation with each element of this sequence.

Declaration

func compactMap(_ transform: (Self.Element) throws -> ElementOfResult?) rethrows -> [ElementOfResult]

你在它的元素上创建一个 Any-array 和 compactMap 只给出 compactMap Any-elements,没有 Optional<Any> 它可以考虑是否为 nil,所以所有元素都保留。

这是因为 [a, b] 被认为是 [Any]。当数组文字中的元素类型完全不相关时(Int?String?),数组类型被推断为 [Any].

在传递给 compactMap 的闭包中,您 return 编辑了 [=19=],其类型为 Any。这意味着 [=19=] 永远不可能是 nil。当您将它们放入数组时,数组中的所有可选值都被包裹在 Any 中。因为你永远不会在闭包中 return a nil,所以所有元素都保留在结果数组中。

编译器可以警告您关于在非可选中包装可选值 Anys:

var a: String? = "abc"

let any: Any = a // warning!

但不幸的是,当您创建数组时它不会警告您。

无论如何,您可以通过指定您想要 [Any?]:

来获得预期的行为
let result = ([a, b] as [Any?]).compactMap { [=11=] }

所以你可以从 Any.

中解开它们

或者:

let result = [a as Any?, b as Any?].compactMap { [=12=] }

Why can an optional type be wrapped inside an Any?

根据 docs(在 AnyAnyObject 的类型转换部分):

Any can represent an instance of any type at all, including function types.

因此,Optional<T>无疑可以表示为Any