当您使用身份转换时{ $0 }
,编译器会推断ElementOfResult?
(变换的结果)相当于Element
(变换的参数)。在这种情况下,Element
is String?
, 所以ElementOfResult?
== String?
。这里不需要可选的促销,所以ElementOfResult
可以推断为String
.
所以flatMap(_:)
在这种情况下返回一个[String]
.
在内部,这种转换来自闭包的返回ElementOfResult?
to ElementOfResult
只需有条件地展开可选值即可完成,如果成功,则展开的值将附加到结果中。您可以看到具体实现在这里 https://github.com/apple/swift/blob/master/stdlib/public/core/SequenceAlgorithms.swift.gyb#L709.
作为附录,请注意正如马丁指出的 https://stackoverflow.com/questions/42213656/how-flatmap-api-contract-transforms-optional-input-to-non-optional-result#comment71588951_42213785,闭包体仅在以下情况下参与类型推断:单语句关闭(参见这个相关的错误报告 https://bugs.swift.org/browse/SR-1570)。乔丹·罗斯给出了这样做的理由在此邮件列表讨论中 https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20151214/002583.html:
Swift 的类型推断目前是面向语句的,因此没有简单的方法来进行[多语句闭包]推断。这至少在一定程度上是一个编译时问题:Swift 的类型系统比 Haskell 或 OCaml 允许更多可能的转换,因此解决整个多语句函数的类型不是一个小问题,也可能不是一个容易处理的问题。
这意味着对于具有多个语句的闭包,这些语句传递给诸如map(_:)
or flatMap(_:)
(其中结果类型是通用占位符),您必须显式注释闭包的返回类型或方法返回本身。
例如,这不会编译:
// error: Unable to infer complex closure return type; add explicit type to disambiguate.
let result = albums.flatMap {
print($0 as Any)
return $0
}
但这些确实:
// explicitly annotate [ElementOfResult] to be [String] – thus ElementOfResult == String.
let result: [String] = albums.flatMap {
print($0 as Any)
return $0
}
// explicitly annotate ElementOfResult? to be String? – thus ElementOfResult == String.
let result = albums.flatMap { element -> String? in
print(element as Any)
return element
}