You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Swift泛型类实现泛型函数时类型转换错误求助

泛型类与泛型函数类型冲突错误分析

错误信息

Cannot convert return expression of type 'Model' to return type 'Model'

问题代码

泛型类代码

public class URLCacheAdapter<Model>:LoaderProtocol{

    public let adaptee:URLCache
    public let mapper: (Data,URLResponse) throws -> Model
    
    public typealias Mapper = (Data,URLResponse) throws -> Model
    
    public init(adaptee: URLCache,
                mapper: @escaping (Data,URLResponse) throws -> Model) {
        self.adaptee = adaptee
        self.mapper = mapper
    }
    
    public enum CacheErrors:Swift.Error{
        case dataNotFound
    }
    
    public func load<Model>() async throws -> Model {
        guard let cachedResponse = adaptee.cachedResponse(for: requet) else{
            throw CacheErrors.dataNotFound
        }
        return mapper(cachedResponse.data,cachedResponse.response) // Error here
    }
}

协议代码

public protocol LoaderProtocol{
    func load<T>() async throws -> T
}

泛型映射器代码

public class DataMapper{

    public enum Errors: Error{
        case invalidData
    }

    public static func map(_ data:Data,from response:HTTPURLResponse) throws -> People{
        guard response.statusCode == 200, let root = try? JSONDecoder().decode(PeopleModel.self, from: data) else{
            throw Errors.invalidData
        }
        return ConvertModelToDto.convertToPeopleData(model: root)
    }
}

问题原因

  1. 泛型重名冲突:类的泛型参数Model和load函数的泛型参数Model是完全独立的两个类型。类的Model由初始化时传入的mapper决定,而函数的Model是调用时指定的任意类型,编译器无法将两者关联,导致返回值类型不匹配。
  2. 协议与类的泛型不兼容:原LoaderProtocol要求load函数能返回任意类型<T>,但URLCacheAdapter类只能返回固定的Model类型,违背了协议要求,进一步加剧类型冲突。
  3. 拼写错误:代码中requet是request的拼写错误,会导致未定义变量问题。

解决方案

1. 修改协议为泛型协议

让协议关联具体类型,匹配类的泛型:

public protocol LoaderProtocol {
    associatedtype Model
    func load() async throws -> Model
}

2. 修正泛型类的load函数

移除函数的泛型参数,直接使用类级别的泛型Model,同时修正拼写错误:

public class URLCacheAdapter<Model>: LoaderProtocol {

    public let adaptee: URLCache
    public let mapper: (Data, URLResponse) throws -> Model
    public let request: URLRequest
    
    public typealias Mapper = (Data, URLResponse) throws -> Model
    
    public init(adaptee: URLCache,
                request: URLRequest,
                mapper: @escaping (Data, URLResponse) throws -> Model) {
        self.adaptee = adaptee
        self.request = request
        self.mapper = mapper
    }
    
    public enum CacheErrors: Swift.Error {
        case dataNotFound
    }
    
    public func load() async throws -> Model {
        guard let cachedResponse = adaptee.cachedResponse(for: request) else {
            throw CacheErrors.dataNotFound
        }
        return try mapper(cachedResponse.data, cachedResponse.response)
    }
}

3. 映射器使用示例

DataMapper的map函数返回固定People类型,初始化URLCacheAdapter时直接传入即可:

let cache = URLCache.shared
let request = URLRequest(url: URL(string: "your-target-url")!)
let adapter = URLCacheAdapter<People>(adaptee: cache, request: request) { data, response in
    guard let httpResponse = response as? HTTPURLResponse else {
        throw DataMapper.Errors.invalidData
    }
    return try DataMapper.map(data, from: httpResponse)
}

内容的提问来源于stack exchange,提问作者Tushar Sharma

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 03:45:12