为什么compactMap返回nil结果?

mrv*_*nzo 10 swift swift4.1

请考虑以下代码段:

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

let result = [a, b].compactMap { $0 }
Run Code Online (Sandbox Code Playgroud)

执行后,result将会

["abc"]
Run Code Online (Sandbox Code Playgroud)

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

print(type(of: result))
Array<String>
Run Code Online (Sandbox Code Playgroud)

现在到了有趣的部分.将代码段更改为

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

let result = [a, b].compactMap { $0 }
Run Code Online (Sandbox Code Playgroud)

并执行它,result将是

[Optional("abc"), nil]
Run Code Online (Sandbox Code Playgroud)

结果的元件(ElementOfResult)这里是Any这是有意义的,因为Any是的公分母StringInt.

print(type(of: result))
Array<Any>
Run Code Online (Sandbox Code Playgroud)

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

来自Apple的compactMap 文档

compactMap(_ :)

返回一个数组,其中包含使用此序列的每个元素调用给定转换的非零结果.

宣言

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

Swe*_*per 5

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

在传递给的闭包中compactMap,你返回$0了类型Any.这意味着$0永远不会nil.数组中的所有选项都包含在Any您将它们放入数组中的那一刻.因为你永远不会nil在闭包中返回a ,所有元素都保留在结果数组中.

编译器可以警告您在非可选的Anys中包装选项:

var a: String? = "abc"

let any: Any = a // warning!
Run Code Online (Sandbox Code Playgroud)

但不幸的是,它在您创建数组时不会发出警告.

无论如何,您可以通过指定您想要的内容来获得预期的行为[Any?]:

let result = ([a, b] as [Any?]).compactMap { $0 }
Run Code Online (Sandbox Code Playgroud)

所以你有点打开它们Any.

要么:

let result = [a as Any?, b as Any?].compactMap { $0 }
Run Code Online (Sandbox Code Playgroud)

为什么可选类型可以包含在Any

根据文档(在类型转换AnyAnyObject部分):

Any 可以表示任何类型的实例,包括函数类型.

因此,Optional<T>毫无疑问可以用Any.

  • @ user1046037`nil`不在结果数组中,但是一个可选的nil只打印`nil`. (2认同)