Swift泛型:基于参数类型的返回类型

Ben*_*Ben 19 generics swift

假设我有一个继承自公共超类的对象集合(在这种情况下,这比协议更可取):

class ObjectSuperClass {
    type: ObjectType
}
class ObjectClass1: ObjectSuperClass {
    type = .Type1
}
class ObjectClass2: ObjectSuperClass {
    type = .Type2
}
Run Code Online (Sandbox Code Playgroud)

我正在寻找这样的通用搜索功能:

func objectsOfType<T: ObjectSuperClass>(T.class, otherFilter: Any?) -> [T]
Run Code Online (Sandbox Code Playgroud)

可用于搜索给定的子类型,返回更具体的结果数组:

let result = objectsOfType(ObjectClass2.class, otherFilter: nil) -> [ObjectClass2]
(pseudo-swift)
Run Code Online (Sandbox Code Playgroud)

我觉得这是generics可以帮助的地方,但无法看到应该放置约束的地方.可能吗?

Jer*_*myP 21

非常值得一提......

func filterType<T>(list: [AnyObject]) -> [T]
{
    return list.filter{ $0 is T }.map{ $0 as! T }
}
Run Code Online (Sandbox Code Playgroud)

...如果您将结果分配给已明确键入的内容,如下例所示:

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>]
Run Code Online (Sandbox Code Playgroud)

在每种情况下根据请求的返回类型推断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>
Run Code Online (Sandbox Code Playgroud)

编辑

该filterType功能的一个更光滑的版本将使用flatMap()

func filterType<T>(list: [Any]) -> [T]
{
    return list.flatMap{ $0 as? T }
}
Run Code Online (Sandbox Code Playgroud)


cou*_*elk 5

这是我能想到的最接近的近似值:

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
}
Run Code Online (Sandbox Code Playgroud)

用法:

let bar = objectsOfType(type: ObjectClass1.self)

let baz = objectsOfType(type: ObjectClass2.self) {
    // Something that returns Bool and uses $0
}
Run Code Online (Sandbox Code Playgroud)

从技术上讲,你也可以去没有type在上面的说法,但是你需要有显式类型的接收器(bar以及baz在上面的例子),使雨燕能够正确地推断出类型为你使用泛型函数的正确版本。