无法转换类型的通用默认参数值

时间:2017-09-04 09:09:37

标签: swift generics

我有一个简单的ParserType,PAT看起来像这样:

public protocol ParserType {
    associatedtype ModelType
    func parse(_ data: Any?) throws -> ModelType
}

我有WebService

public class WebService<ModelType, Parser: ParserType> {

    public typealias ModelType = Parser.ModelType
    private let parser: Parser
    ...

    public init(transport: ServiceTransport, endpoint: String, parser: Parser) {
        self.transport = transport
        self.endpoint = endpoint
        self.parser = parser
    }

    func fetch(...) -> ModelType {
        ...
        let result: ModelType = try! self.parser.parse(data)
        return result
    }
}

一个简单的解析器:

public class SimpleJSONParser<T: Codable>: ParserType {

    public typealias ModelType = T
    private let jsonDecoder: JSONDecoder

    public init(jsonDecoder: JSONDecoder = JSONDecoder()) {
        self.jsonDecoder = jsonDecoder
    }

    open func parse(_ data: Any?) throws -> T {
        let response = try jsonDecoder.decode(T.self, from: data as! Data)
        return response
    }
}

这可以按预期工作。

但是,当我想添加一个带有默认解析器的WebService子类时,即

class SimpleWebService<T: Codable, Parser: ParserType> : WebService<T, Parser> {

    override init(transport: ServiceTransport, endpoint: String, parser: Parser = SimpleJSONParser<T>()) {
        super.init(transport: transport, endpoint: endpoint, parser: parser)
    }
}

我收到以下错误: Default argument value of type 'SimpleJSONParser<T>' cannot be converted to type 'Parser'。我认为SimpleJSONParser遵守ParserType,但编译器似乎不这么认为。那是为什么?

1 个答案:

答案 0 :(得分:1)

通过保留Parser泛型,SimpleWebServer可以使用除SimpleJSONParser以外的解析器类型进行实例化(例如let service = SimpleWebService<..., SimpleXMLParser>(...),因此SimpleJSONParser与通用之间存在冲突键入Parser,专门用于SimpleXMLParser

因此,您必须在扩展中使用通用的相同类型约束来为初始化程序添加默认值:

extension SimpleWebService where Parser == SimpleJSONParser<T> {
    convenience init(transport: ServiceTransport, endpoint: String, parser: Parser = SimpleJSONParser<T>()) {
        super.init(transport: transport, endpoint: endpoint, parser: parser)
    }
}

但请注意,此代码无法编译,因为目前不允许覆盖扩展中的方法。