我喜欢@stefreak 的问题和他的解决方案。然而,牢记@dfri 对 Swift 运行时自省的出色回答,我们可以在一定程度上简化和概括@stefreak 的“类型标记”方法:
protocol AnySequenceType {
var anyElements: [Any?] { get }
}
extension AnySequenceType where Self : SequenceType {
var anyElements: [Any?] {
return map{
$0 is NilLiteralConvertible ? Mirror(reflecting: $0).children.first?.value : $0
}
}
}
extension Array : AnySequenceType {}
extension Set : AnySequenceType {}
// ... Dictionary, etc.
采用:
let things: Any = [1, 2]
let maybies: Any = [1, nil] as [Int?]
(things as? AnySequenceType)?.anyElements // [{Some 1}, {Some 2}]
(maybies as? AnySequenceType)?.anyElements // [{Some 1}, nil]
有关允许协议扩展的可能性,请参阅Swift Evolution 邮件列表讨论:
extension<T> Sequence where Element == T?
然而,在目前的实践中,更常见且有些虎头蛇尾的解决方案是:
things as? AnyObject as? [AnyObject] // [1, 2]
// ... which at present (Swift 2.2) passes through `NSArray`, i.e. as if we:
import Foundation
things as? NSArray // [1, 2]
// ... which is also why this fails for `mabyies`
maybies as? NSArray // nil
无论如何,这一切让我明白的是,一旦你丢失了类型信息,就没有回头路了。即使你反思Mirror
你最终还是会得到一个dynamicType
,你必须切换到一个预期的类型,这样你就可以转换值并像这样使用它......所有这些都在运行时,永远在编译时检查和理智之外。