请考虑以下代码段:
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是的公分母String和Int.
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]
这是因为[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?
根据文档(在类型转换Any和AnyObject部分):
Any可以表示任何类型的实例,包括函数类型.
因此,Optional<T>毫无疑问可以用Any.
| 归档时间: |
|
| 查看次数: |
694 次 |
| 最近记录: |