扩展Swift数组以按类型过滤元素 [英] Extend Swift Array to Filter Elements by Type

查看:80
本文介绍了扩展Swift数组以按类型过滤元素的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何将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数组以按类型过滤元素的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆