假设我有一个从公共超类继承的对象集合(在这种情况下,这比协议更可取):
class ObjectSuperClass {
type: ObjectType
}
class ObjectClass1: ObjectSuperClass {
type = .Type1
}
class ObjectClass2: ObjectSuperClass {
type = .Type2
}
我正在寻找创建这样的通用搜索功能:
func objectsOfType<T: ObjectSuperClass>(T.class, otherFilter: Any?) -> [T]
可用于搜索给定的子类型,返回更具体的结果数组:
let result = objectsOfType(ObjectClass2.class, otherFilter: nil) -> [ObjectClass2]
(pseudo-swift)
我觉得这是generics可以帮助的地方,但是看不到应该放置约束的地方。有可能吗?
答案 0 :(得分:16)
非常值得一提......
func filterType<T>(list: [AnyObject]) -> [T]
{
return list.filter{ $0 is T }.map{ $0 as! T }
}
...如果您将结果分配给已明确键入的内容,如下例所示:
class ObjectSuperClass: CustomStringConvertible
{
let myType: String
init(aString: String)
{
myType = aString
}
var description: String { return myType }
}
class ObjectClass1: ObjectSuperClass
{
init()
{
super.init(aString: "<t 1>")
}
}
class ObjectClass2: ObjectSuperClass
{
init()
{
super.init(aString: "<t 2>")
}
}
let unfilteredList: [AnyObject] = [ ObjectClass1(), ObjectClass2(), ObjectSuperClass(aString: "<Who knows>")]
let filteredList1: [ObjectClass1] = filterType(list: unfilteredList)
print("\(filteredList1)") // <t 1>
let filteredList2: [ObjectClass2] = filterType(list: unfilteredList)
print("\(filteredList2)") // <t 2>
let filteredList3: [ObjectSuperClass] = filterType(list: unfilteredList)
print("\(filteredList3)") // [<t 1>, <t 2>, <Who knows>]
在每种情况下根据请求的返回类型推断T.函数本身根据元素是否为所需类型过滤原始数组,然后强制将过滤后的结果转换为正确的类型。
如果你想要一个“额外过滤器”,只要可以从你的额外过滤器函数推断出T,你就不需要显式地输入结果。
func extraFilterType<T>(list: [AnyObject], extraFilter: T -> Bool) -> [T]
{
return list.filter{ $0 is T }.map{ $0 as! T }.filter(extraFilter)
}
let filteredList = extraFilterType(unfilteredList){
(element : ObjectClass2) -> Bool in
!element.description.isEmpty
}
print("\(filteredList)") // <t 2>
修改强>
filterType
函数的滑动版本将使用flatMap()
func filterType<T>(list: [Any]) -> [T]
{
return list.flatMap{ $0 as? T }
}
答案 1 :(得分:3)
这是我能提出的最接近的近似值:
func objectsOfType<T: ObjectSuperClass>(type type: T.Type) -> [T] {
// Just returns an array of all objects of given type
}
func objectsOfType<T: ObjectSuperClass>(type type: T.Type, predicate: T -> Bool) -> [T] {
// Uses predicate to filter out objects of given type
}
用法:
let bar = objectsOfType(type: ObjectClass1.self)
let baz = objectsOfType(type: ObjectClass2.self) {
// Something that returns Bool and uses $0
}
从技术上讲,你也可以在上面没有type
参数,但是你需要在上面的例子中明确键入接收器(bar
和baz
)以便Swift可以正确地为您推断类型,并使用正确的通用函数版本。
答案 2 :(得分:1)
您可以实现这样的功能:
func objectsOfType<T: ObjectSuperClass>(objects: [ObjectSuperClass], subclass: T.Type, otherFilter: (T->Bool)?) -> [T] {
if let otherFilter = otherFilter {
return objects.filter{$0 is T && otherFilter($0 as! T)}.map{$0 as! T}
} else {
return objects.filter{$0 is T}.map{$0 as! T}
}
}
用法示例:
objectsOfType(arrayOfObjects, subclass: ObjectClass1.self, otherFilter: nil)
请注意,我不是强制转换的粉丝,但在这种情况下,它不应该导致问题。
或者,更详细的函数版本,少了一个强制转换:
func objectsOfType<T: ObjectSuperClass>(objects: [ObjectSuperClass], subclass: T.Type, otherFilter: (T->Bool)?) -> [T] {
return objects.filter({object in
if let object = object as? T {
if let otherFilter = otherFilter {
return otherFilter(object)
} else {
return true
}
} else {
return false
}
}).map({object in
return object as! T
})
}