【问题标题】:Default argument value of type 'JSONEncoder' cannot be converted to type 'Encoder' (TopLevelEncoder)'JSONEncoder' 类型的默认参数值无法转换为'Encoder' 类型(TopLevelEncoder)
【发布时间】:2019-10-22 06:51:16
【问题描述】:

我尝试创建一个通用方法,该方法接受 TopLevelEncoderTopLevelDecoder 以使其可注入(例如,JSONEncoder 用于生产代码,CustomEncoder 用于测试)。由于这两个协议都有关联的类型,我限制了它们的类型,而不仅仅是做encoder: TopLevelEncoder = JSONEncoder()。我想出了这个方法:

func test<Encoder, Decoder>(
    encoder: Encoder = JSONEncoder(),
    decoder: Decoder = JSONDecoder()
) where Encoder: TopLevelEncoder, Decoder: TopLevelDecoder {
    //encode and decode
}

编译器给了我以下错误信息:Default argument value of type 'JSONEncoder' cannot be converted to type 'Encoder'。我不明白它为什么不能转换为Encoder 类型,因为JSONEncoder 继承自TopLevelEncoder

我可能误解了泛型和associatedType 的工作原理,但我也无法理解这个错误消息。有人可以帮帮我吗?

我已经看到了解决这个问题的其他方法,比如创建一个新协议,如 AnyEncoder 并用它扩展 JSONEncoder。但在我看来,使用现有协议会更干净。我的方法也需要TopLevelDecoder,因为我使用的是URLSessionss .dataTaskPublisher (.decode(...))。

【问题讨论】:

标签: swift generics dependency-injection combine


【解决方案1】:

我不知道在这种情况下强制转换有多安全,但这似乎可以编译和工作:

struct User: Codable {
    var name: String
}

func decodeEncode<Encoder, Decoder>(
  encoder: Encoder = JSONEncoder() as! Encoder, 
  decoder: Decoder = JSONDecoder() as! Decoder) 
  where Encoder: TopLevelEncoder, Decoder: TopLevelDecoder, 
        Encoder.Output == Data, Decoder.Input == Data
{
    let bruceData = try! encoder.encode(User(name: "Bruce Lee"))
    let bruce = try! decoder.decode(User.self, from: bruceData)

    print("bruce: \(bruce)")
}

decodeEncode(encoder: JSONEncoder(), decoder: JSONDecoder())

可以限制Encoder.Output == Decoder.Input,但我已明确指定Data,因为JSONEncoderJSONDecoder 都适用于Data

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-03-21
    • 2016-07-27
    • 2016-07-02
    • 2021-10-17
    • 2016-10-11
    • 2020-03-01
    • 2016-08-01
    • 2017-02-07
    相关资源
    最近更新 更多