簡體   English   中英

Swift泛型:基於參數類型的返回類型

[英]Swift generics: return type based on parameter type

假設我有一個繼承自公共超類的對象集合(在這種情況下,這比協議更可取):

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可以幫助的地方,但無法看到應該放置約束的地方。 可能嗎?

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

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 }
}

編輯2

對於選項,不推薦使用compactMap ,因為Swift 4.something使用了compactMap

func filterType<T>(list: [Any]) -> [T]
{
    return list.compactMap{ $0 as? T }
}

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

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參數,但是你需要有明確的類型接收器(上例中的barbaz ),以便Swift可以正確地為你推斷類型並使用正確的泛型版本功能。

你可以實現這樣的功能:

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
    })
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM