【问题标题】:Swift Generics Generic parameter could not be inferred无法推断 Swift Generics 通用参数
【发布时间】:2022-01-28 08:42:39
【问题描述】:

我正在尝试创建一个具有泛型参数函数的协议。

protocol APIRequest {
    static func fetchData<T: Codable>(completion: @escaping(T?, NetworkError?) -> Void)
}

那么我有一个符合协议的结构

static func fetchData<Ztar: Codable>(completion: @escaping (Ztar?, NetworkError?) -> Void) {
        let url = URLConstructor.url(scheme: "https", host: "swapi.dev" , path: "/api")
        guard let url = url else { return }
        let task = URLSession.shared.dataTask(with: url) { data, response, error in
            guard let data = data else {
                completion(nil, NetworkError.badResponse)
                return
            }
            do {
                let decoder = JSONDecoder()
                let object = try decoder.decode(Ztar.self, from: data)
                completion(object, nil)
            } catch {
                print(error)
            }
        }
        task.resume()
    }

但我不确定泛型类型的实现是否正确,因为在我的ViewController 中,我收到错误无法推断泛型参数“Ztar”

NetworkManager.fetchData { star, error in
            
}

谁能解释我做错了什么?

【问题讨论】:

    标签: swift generics protocols


    【解决方案1】:

    无法正确实施。 Ztar是什么类型的?编译器怎么知道?你写过“fetchData 将从宇宙中所有无限可能的数据中获取某种数据,而你,编译器,应该解码它。”这是不可能的。

    相反,这通常是这样写的:

    fetchData<T: Codable>(ofType: T.Type, completion: @escaping (Result<T, NetworkError>) -> Void)
    

    然后您需要将您期望的类型作为第一个参数传递:

    fetchData(ofType: Record.self) { resultRecord in ... }
    

    如果你不知道Ztar是什么类型,编译器怎么可能?

    (请注意,您几乎不应该使用 (T?, Error?) 作为类型。这表示“可能是 T,可能是 Error,可能两者都不是,也可能两者兼而有之。”您几乎总是指的是 Result&lt;T, Error&gt;,而是说“T 或 Error .")

    【讨论】:

    • 或者简单地fetchData&lt;T: Codable&gt;(completion: @escaping (Result&lt;T, NetworkError&gt;) -&gt; Void)和当调用fetchData { (result: Result&lt;Record, NetworkError&gt;) in ... }
    • @Rob Napier 感谢您的回复。所以这是每次我需要让编译器知道什么是类型时的主要问题?并且类型应该始终在实现中?
    • @Robert 不然会怎样?考虑一个任意 JSON 对象。您将如何将其解码为任何可能存在的类型?如果不知道 JSON 的类型,编译器怎么可能?
    • @LeoDabus 这种语法使用起来更令人讨厌。最好将类型直接包含在调用中的某个位置,例如在 Decodable 中。您可以添加ofType: T.Type = T.self,当类型很明显时,它作为快捷方式非常好,但您不应该将其完全删除。
    • @RobNapier 明白了,如果我也不知道编译器的类型,这是有道理的。谢谢你的解释
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-11-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多