簡體   English   中英

在 iOS Swift 中重載泛型函數

[英]Overloading generic functions in iOS Swift

我正在嘗試構建一個查找器,該查找器嘗試並找到在閉包內傳遞給它的多種類型。

enum SomeError: Error {
    case notInitialized
}

struct TestFinder {

    func getSomething<T, U>(_ function: @escaping (T) -> U) throws -> U {
        guard let t: T = get() else {
                throw SomeError.notInitialized
        }

        return function(t)
    }

    func getSomething<T, U, V>(_ function: @escaping (T, U) -> V) throws -> V {
        guard let t: T = get(), let u: U = get() else {
                throw SomeError.notInitialized
        }

        return function(t, u)
    }

    func getSomething<T, U, V, W>(_ function: @escaping (T, U, V) -> W) throws -> W {
        guard let t: T = get(), let u: U = get(), let v: V = get() else {
                throw SomeError.notInitialized
        }

        return function(t, u, v)
    }

    private func get<T>() -> T? {
       nil
    }
}

struct UserDetails {
    let name: String
    let roll: String
}

我稱取景器為:

let testReturnType = try? TestFinder().getSomething(UserDetails.init)

編譯器給我一個錯誤:

'getSomething' 的模糊使用

此錯誤的原因(來自文檔):

您可以通過在類型參數上提供不同的約束、要求或兩者來重載通用 function 或初始化程序。 當您調用重載的泛型 function 或初始化程序時,編譯器使用這些約束來解析要調用的重載 function 或初始化程序。

但如果我評論:

func getSomething<T, U>(_ function: @escaping (T) -> U) throws -> U

一切都開始工作。 它與編譯器無法識別要解析的 function 簽名有關。

對此有什么特別的解決方案嗎?

您還沒有完全關注實際問題。 讓我們消除與示例無關的所有內容。 這可以按預期編譯和工作:

struct TestFinder {

    func doSomething<T,U>(_ function: (T,U) -> Void) -> Void {
        print("two")
    }

    func doSomething<T,U,V>(_ function: (T,U,V) -> Void) -> Void {
        print("three")
    }

    func doSomething<T,U,V,W>(_ function: (T,U,V,W) -> Void) -> Void {
        print("four")
    }

}

在這里我們將對其進行測試:

    func f(_ s1: String, _ s2: String, _ s3: String, _ s4: String) -> Void {}
    TestFinder().doSomething(f) // "four"

但是如果你添加一個傳遞了 function 參數的版本,一切都會崩潰:

struct TestFinder {

    func doSomething<T>(_ function: (T) -> Void) -> Void {
        print("one")
    }

    func doSomething<T,U>(_ function: (T,U) -> Void) -> Void {
        print("two")
    }

    func doSomething<T,U,V>(_ function: (T,U,V) -> Void) -> Void {
        print("three")
    }

    func doSomething<T,U,V,W>(_ function: (T,U,V,W) -> Void) -> Void {
        print("four")
    }
}

現在我們無法編譯,因為第一個版本被視為候選版本。 事實上,如果我們刪除其他版本,我們仍然可以編譯!

struct TestFinder {

    func doSomething<T>(_ function: (T) -> Void) -> Void {
        print("one")
    }

}

這就是奇怪的部分。 我們仍然編譯,即使我們說:

    func f(_ s1: String, _ s2: String, _ s3: String, _ s4: String) -> Void {}
    TestFinder().doSomething(f)

顯然,這個帶有四個參數的 function 被編譯器視為只用一個通用參數“擬合”了聲明。

我認為這是一個錯誤。 我想我可以猜到可能導致它的原因; 它可能與 function 參數列表作為元組的遺留問題有關。 此 function f與采用由四字符串元組組成的單個參數的 function “等效”。 盡管如此,您實際上不能在doSomething中使用四字符串元組調用function 我根本找不到調用它的方法。

所以,我想說,把它當作一個錯誤,現在通過刪除你的泛型的第一個版本來解決它。


更新:根據 Swift 團隊的建議,我使用 2020 年 5 月 4 日的 Swift 5.3 開發工具鏈進行了測試。 有了它,您的代碼將按預期進行編譯和運行。 這確實是一個錯誤,它已作為

https://bugs.swift.org/browse/SR-8563

回到我的版本,我的代碼也按預期編譯和運行,所有四個版本的doSomething都存在。 但是,請注意,如果您刪除除了第一個版本的doSomething之外的所有內容,它仍然可以編譯並運行。 此外,您可以使用四個參數調用function ,方法是將它們捆綁到一個元組中並強制轉換,如下所示:

struct TestFinder2 {

    func doSomething<T>(_ function: (T) -> Void) -> Void {
        print("one")
        function(("manny", "moe", "jack", "henry") as! T)
    }

}

這似乎證實了我的猜測,即您所看到的是函數參數列表的隱藏元組性質的結果。 人們可以從對 bug 的討論中得出相同的結論,即“tuple-splatting”。

關鍵是 UserDetails 結構體,因為這個結構體有兩個屬性並且沒有任何設計的初始化器,初始化器可以是 UserDetails(name: , roll: ) 或 UserDetails(name: ) 或 UserDetails(roll: ),這是雄心勃勃的部分. 如果您只是刪除 UserDetails 的一個也可以使用的屬性,因為一個屬性結構只有一個設計的初始值設定項。

如果你評論

func getSomething<T, U>(_ function: @escaping (T) -> U) throws -> U

這意味着查找器只有一個選擇:

func getSomething<T,U,V>(_ function: @escaping(T,U) -> V) throws -> V

暫無
暫無

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

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