如何将swift数组扩展为访问特定类型的成员?
How can a swift array be extended to access members of a particular type?
如果数组包含从同一个超类继承的多个类的实例,则此方法相关。理想情况下,它将适当地执行类型检查。
This is relevant if an array contains instances of multiple classes which inherit from the same superclass. Ideally it would enforce type checking appropriately.
使用 filter(_:)方法可以正常工作,但确实可以保证类型安全。例如:
Using the filter(_:) method works fine, but does enforce type safety. For example:
protocol MyProtocol { } struct TypeA: MyProtocol { } struct TypeB: MyProtocol { } let myStructs:[MyProtocol] = [ TypeA(), TypeA(), TypeB() ] let filteredArray = myStructs.filter({ $0 is TypeA })filteredArray 包含正确的值,但是类型保持为 [MyProtocol] 而不是 [TypeA] 。我希望将最后一个替换为 letfilteredArray = myStructs.filter({$ 0是TypeA})! [TypeA] 可以解决该问题,但是项目失败,并显示 EXEC_BAD_INSTRUCTION ,我不明白。也许类型转换数组是不可能的?
the filteredArray contains the correct values, but the type remains [MyProtocol] not [TypeA]. I would expect replacing the last with let filteredArray = myStructs.filter({ $0 is TypeA }) as! [TypeA] would resolve that, but the project fails with EXEC_BAD_INSTRUCTION which I do not understand. Perhaps type casting arrays is not possible?
理想情况下,此行为可以包装在数组扩展中。以下内容无法编译:
Ideally this behavior could be wrapped up in an array extension. The following doesn't compile:
extension Array { func objectsOfType<T:Element>(type:T.Type) -> [T] { return filter { $0 is T } as! [T] } }这里似乎至少有两个问题:类型约束 T:Element 似乎不起作用。我不确定基于泛型类型添加约束的正确方法是什么。我的目的是说 T 是 Element 的子类型。另外,在第3行上存在编译时错误,但这可能与传播错误相同。
Here there seem to be at least two problems: the type constraint T:Element doesn't seem to work. I'm not sure what the correct way to add a constraint based on a generic type. My intention here is to say T is a subtype of Element. Additionally there are compile time errors on line 3, but this could just be the same error propagating.
推荐答案SequenceType 具有 flatMap()方法,该方法用作可选过滤器:
SequenceType has a flatMap() method which acts as an "optional filter":
extension SequenceType { /// Return an `Array` containing the non-nil results of mapping /// `transform` over `self`. /// /// - Complexity: O(*M* + *N*), where *M* is the length of `self` /// and *N* is the length of the result. @warn_unused_result @rethrows public func flatMap<T>(@noescape transform: (Self.Generator.Element) throws -> T?) rethrows -> [T] }结合了Matt的建议使用作为?代替是,您可以将其用作
Combined with matt's suggestion to use as? instead of is you can use it as
let myStructs:[MyProtocol] = [ TypeA(), TypeA(), TypeB() ] let filteredArray = myStructs.flatMap { $0 as? TypeA }现在 filteredArray 的类型为推断为 [TypeA] 。
作为扩展方法,应为
extension Array { func objectsOfType<T>(type:T.Type) -> [T] { return flatMap { $0 as? T } } } let filteredArray = myStructs.objectsOfType(TypeA.self)注意:对于 Swift> = 4.1,用 compactMap替换 flatMap code>。
Note: For Swift >= 4.1, replace flatMap by compactMap.
更多推荐
扩展Swift数组以按类型过滤元素
发布评论