簡體   English   中英

如何從協議實現中確定泛型類型

[英]How to determine the generic type from protocol implementation

我有一個協議,其函數可以返回String[String: String] 這是我的聲明:

protocol Test {
  associatedtype T: Hashable
  func returnSomething() -> T
}

然后我想要一個returnSomething的默認實現,所以我做了一個協議擴展:

extension Test {
    func returnSomething() -> T {
         let valueToReturn = readValueFromPLISTthatCanReturnAStringOrDictionary() as T
        return valueToReturn
    }
}

所以最后我有兩個部分, TestStringTestDictionary都實現了Test協議,我想指出T參數,我想使用默認實現。 我是怎么做到的

class TestString: Test {}

class TestDictionary: Test { }

class TestString: Test where Test.T = String or similar?

我有一個協議,其函數可以返回String或[String:String]。 這是我的聲明:

沒問題。 讓我們寫下來。

enum StringOrDictionary {
    case string(String)
    case dictionary([String: String])
}

protocol Test {
    func returnSomething() -> StringOrDictionary
}

然后我想要一個returnSomething的默認實現,所以我做了一個協議擴展:

聽起來不錯。 我假設readValueFromPLISTthatCanReturnAStringOrDictionary()實際上返回Any ,因為這是propertyList(from:)返回的內容。

extension Test {
    func returnSomething() -> StringOrDictionary {
        let value = readValueFromPLISTthatCanReturnAStringOrDictionary()

        switch value {
        case let string as String: return .string(string)
        case let dictionary as [String: String]: return .dictionary(dictionary)
        default: fatalError() // Or perhaps you'd like to do something else
        }
    }
}

將你的類型命名為比StringOrDictionary更有意義的東西可能會StringOrDictionary ,但StringOrDictionary ,它應該非常簡單。 只做一個意味着你說的話。 你想要一個意味着“OR”的類型,這是一個枚舉。 (如果你想要一個意味着“AND”的類型,那就是結構BTW。)


關於你的答案,這是不合法的:

class RandomClass: Test where Test.T == String {
    func getValue() {
        let bah = doSomething() // I don't need here to specify bah's type.
    }
}

定義T是實現所需的方法。

class RandomClass: Test {
    func returnSomething() -> String {
        return ""
    }
}

如果您想共享一些公共代碼,那么您可以將其作為擴展而不是默認實現附加。 您可以編寫一個returnString()方法並從RandomClass.returnSomething()中調用它。 這在某些情況下非常有用,但在這種情況下我絕對不會使用它。 你的意思並不是“返回任何可能的類型(T)。” 你的意思是“返回兩種可能的類型之一”,這是一個枚舉,而不是一般。

更新:顯然他們已經添加了一個他們已經談過的新功能,但我認為還沒有。 您現在可以這樣實現RandomClass

class RandomClass: Test {
    typealias T = String
}

(這是一個非常好的新功能,即使它不是這個問題的好答案。)

這是您當前問題的解決方案:

創建協議的2個子類型,每個子類型具有不同的關聯類型定義,以及不同的默認實現。 您可以通過在兩個子類型之間進行選擇來選擇您希望類使用的默認實現。

這里的下一個問題是[String: String]不是Hashable 這是因為缺乏對條件一致性的支持(例如,如果密鑰和值都是Hashable ,則表示DictionaryHashable的能力),這是Swift最大的垮台之一,即IMO。 您可能希望使用類型擦除包裝器AnyHashable

protocol ResultProvider {
  associatedtype Result: Hashable
  func getResult() -> Result
}

protocol StringResultProvider: ResultProvider {
    typealias Result = String
}

extension StringResultProvider {
    func getResult() -> String {
        return "A string result"
    }
}

protocol IntResultProvider: ResultProvider {
    typealias Result = Int
}

extension IntResultProvider {
    func getResult() -> Int {
        return 123
    }
}

class TestIntResult: IntResultProvider {}
class TestString: StringResultProvider {}

print(TestString().getResult())
print(TestIntResult().getResult())


// protocol DictionaryResultProvider: ResultProvider {
//     typealias Result = [String: String]
// }

// extension DictionaryResultProvider {
//     func getResult() -> [String: String] {
//         return ["A dictionary": "result"]
//     }
// }

// class TestDictionaryProvider: DictionaryResultProvider {}

擴展類時需要指定typealias,如下所示:

protocol Test {
    associatedtype T: Hashable
    func returnSomething() -> T
}

extension String: Test {
    typealias T = Int
}

func def() -> Int {
    return 6
}

extension Test {
    func returnSomething() -> T {
        return def() as! Self.T
    }
}

"".returnSomething()

6

但是,如果沒有強制投射,我找不到辦法。

唯一可行的解​​決方案是在函數中使用泛型,並在調用函數時指定變量類型。 當我在類中實現協議時,我想知道是否可以指定T類型,類似這樣:

class RandomClass: Test where Test.T == String {
    func getValue() {
        let bah = doSomething() // I don't need here to specify bah's type.
    }
}

但前面的例子只是不起作用,所以另一種選擇可能是這樣的:

protocol Test {
    func doSomething<T>() -> T
}

extension Test {
    func doSomething<T>(key: String) -> T {
        return returnDictOrStringFromPLIST(key: key) as! T
    }
}

class TestString: Test {
    func getValue() {
        let bah: String = doSomething()

    }
}

class TestDict: Test {
    func getValue() {
        let bah: [String: String] = doSomething()

    }
}

暫無
暫無

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

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