【问题标题】:type inference error in the callback回调中的类型推断错误
【发布时间】:2018-05-31 05:57:48
【问题描述】:

我遇到了无法解决的类型推断错误。我在下面附上了最重要的sn-p。解析过程由APIClient中的Decoder单独完成。

为什么APIClientexecute 不能识别T[Chapter],因为completion(Result.success(decodedData)) 具有这种类型?

func loadFeed(completion: @escaping (Result<[Chapter]>) -> Void) {
    APIClient.shared.execute(APIRequest.loadFeed) { response in

        guard let decodedData = response.decodedData else { return }
        completion(Result.success(decodedData))
    }
}

上面的 sn-p 是我在 Services 类中调用 APIClient 的方式。

class APIClient: APIClientProtocol {
    static let shared = APIClient()
    func execute<T: Decodable>(_ apiRequest: APIRequestDefining,
                               responseDecoder: ResponseDecoder = .jsonDecoding,
                               completionHandler: @escaping (Response<T>) -> Void) {
        var response = Response<T>(request: request, httpResponse: dataResponse.response, data: dataResponse.data)

        do {
            try responseDecoder.decode(response: &response)
        } catch {
            response.error = error
        }

        completionHandler(response)
    }
}



public struct Response<T> {
    var decodedData: T?
}



enum Result<Value> {
    case success(Value)
    case failure(Error)
}

编辑: 澄清一下,下面的 sn-p 是我 decode 对推断对象的原始响应的位置和方式。

struct JSONResponseDecoder: ResponseDecoding {
    func decode<T: Decodable>(response: inout Response<T>) throws {
        guard let data = response.data else { return }
        do {
            try response.decodedData = JSONDecoder().decode(T.self, from: data)
        } catch {
            throw(ApplicationError(errorType: .decodingError))
        }
    }
}

编辑!!!!:

我发现了一件很奇怪的事情,我把guard的那行去掉了,一切正常,这是为什么呢?

之前 之后

【问题讨论】:

  • 编译器从哪里推断类型?该类型在呼叫站点没有其他用途。
  • @Avi 没有 completion(Result.success(decodedData)) 做这项工作?我想它会匹配 decodedData[Chapter]
  • 连接完全在您的脑海中。代码中没有任何内容将外部loadFeed() 调用的特化与对execute() 的调用联系起来。 Result&lt;T&gt;Response&lt;T&gt; 的类型并不完全相同。

标签: ios swift networking callback type-inference


【解决方案1】:

您说,“执行不承认 T 是 [Chapter]”,我想知道您为什么会这样期望。

你有一个 loadFeed 函数,它有一个使用泛型 Chapter 的完成块。

那么你就有了一个泛型类型 T 的 execute 方法。当你调用你的 execute 方法时,它对 Chapter 类型一无所知。

我遇到与您相同的错误的示例:

 func execute<T>(completionHandler: @escaping (T) -> Void) {

 }
 self.execute { (result) in
 }

解决方案是转换参数以便可以推断出 T。在你的情况下:

func execute<T>(completionHandler: @escaping (T) -> Void) {

 }
 self.execute { (result:[Chapter]) in
 }

泛型很棒:)

【讨论】:

  • 您好,我更新了我的问题,您可以看看吗?
【解决方案2】:

你的 completionHandler 接受一个泛型类型的参数,所以在闭包中明确你的类型,否则它无法推断类型:

func loadFeed(completion: @escaping (Result<[Chapter]>) -> Void) {
    APIClient.shared.execute(APIRequest.loadFeed) { (chapters: [Chapter]) -> () in

        guard let decodedData = chapters.decodedData else { return }
        completion(Result.success(decodedData))
    }
}

【讨论】:

  • 你能解释一下为什么在我的实现中,completion(Result.success(decodedData)) 行不会推断出completion: @escaping (Result&lt;[Chapter]&gt; 的 T 是[Chapter]。这样response 就知道自己是如何被推断出来的。
  • 告诉我T 变成[Chapter] 的确切位置?
  • @crom87 说得很好:“......你有一个泛型类型 T 的执行方法。当你调用你的执行方法时,它对类型 Chapter 一无所知。”跨度>
  • 您好,我更新了我的问题,您可以看看吗?
  • 我的答案是一样的,明确你的类型。
【解决方案3】:

我已经通过另一个帖子找到了答案。

错误原因是编译器只在闭包中只有一条语句时才引用闭包返回类型。

https://forums.swift.org/t/problems-with-closure-type-inference/11859/2

【讨论】:

    猜你喜欢
    • 2022-08-03
    • 2014-06-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-10-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多