请考虑以下代码段:
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
,这很有意义,因为Any
是String
和Int
的公分母。
print(type(of: result))
Array<Any>
为什么nil
返回的compactMap
结果与定义相反?
来自Apple的compactMap
documentation
compactMap(_:)
返回一个数组,其中包含对该序列的每个元素调用给定转换的非零结果。
声明
func compactMap(_ transform:(Self.Element)throws-> ElementOfResult?)重新抛出-> [ElementOfResult]
答案 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(在Any
和AnyObject
的类型转换中):
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>
,它可以考虑是否为零,因此所有要素都保留了。