为什么compactMap返回nil结果?

时间:2018-08-18 08:10:08

标签: swift swift4.1

请考虑以下代码段:

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

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

执行后,result

["abc"]

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

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

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

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

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

并执行它,result

[Optional("abc"), nil]

这里结果(ElementOfResult的元素是Any,这很有意义,因为AnyStringInt的公分母。

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

为什么nil返回的compactMap结果与定义相反?

来自Apple的compactMap documentation

  

compactMap(_:)

     

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

     

声明

     

func compactMap(_ transform:(Self.Element)throws-> ElementOfResult?)重新抛出-> [ElementOfResult]

2 个答案:

答案 0 :(得分:5)

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

在传递给compactMap的闭包中,您返回了$0,其类型为Any。这意味着$0永远不会是nil。将数组中的所有可选元素放入数组后,它们都被包装在Any中。因为您永远不会在闭包中返回nil,所以所有元素都保留在结果数组中。

编译器会警告您有关将可选变量包装在非可选Any中的情况:

var a: String? = "abc"

let any: Any = a // warning!

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

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

let result = ([a, b] as [Any?]).compactMap { $0 }

因此,您可以将它们从Any中解包。

或者:

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

为什么可以将可选类型包装在Any内?

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

  

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

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

答案 1 :(得分:1)

您创建了一个Any-array,compactMap在其元素上仅提供了#userdiv { margin-top: 200px; width: 200px; height: 400px; border: 1px solid red; } a { color: #337ab7; cursor: pointer; } a:hover { text-decoration: underline; }个Any-elements,没有一个<a onclick="scrollSmoothTo('userdiv')"> Scroll to userdiv </a> <div id="userdiv"> Lorem ipsum this is a random text </div>,它可以考虑是否为零,因此所有要素都保留了。