扩展Swift数组以按类型过滤元素 [英] Extend Swift Array to Filter Elements by Type
问题描述
如何将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屋!