符合协议的更指定的扩展版本



假设有一个空协议来限制类型:

public protocol DataType { }
protocol Parser {
func parseData<T: DataType>(_ data: Data, to: T.Type) throws -> T
}

所以我们需要一个专门用于解析 JSON 对象的解析器:

typealias DecodableDataType = Decodable & DataType
protocol JSONParser: Parser {
var jsonDecoder: JSONDecoder { get }
func parseData<T: DecodableDataType>(_ data: Data, to: T.Type) throws -> T
}

因此,它也符合parser需求,并且已经定义了jsonDecoder,因此一个简单的extension会很棒:

extension JSONParser {
func parseData<T: DecodableDataType>(_ data: Data, to: T.Type) throws -> T { try jsonDecoder.decode(T.self, from: data) }
}

因此,如果我们为此实现一个管理器类:

class JSONParsingManager: JSONParser {
public var jsonDecoder: JSONDecoder
init(jsonDecoder: JSONDecoder) {
self.jsonDecoder = jsonDecoder
}
}

期望一切自动运行,但它会抛出:

类型"JSONParsingManager"不符合协议"解析器">

我错过了什么?我需要为其他序列化程序(如 Protobuf 解析器等(定义管理器,所以我不能首先遵守Decodable


更多澄清:

另一个应该以相同方式工作的协议:

protocol ProtobufParser: Parser {
func parseData<T: Message>(_ data: Data, to: T.Type) throws -> T
}
extension ProtobufParser {
func parseData<T: Message>(_ data: Data, to: T.Type) throws -> T { try T.init(serializedData: data) }
}

更新

我无法定义独立协议,因为有一个函数需要获取任何类型的Parser来解析任何可解析的对象。

附言这个问题可能以前被问过,有不同的标题和场景。如果您知道如何提出这个问题,请随时提及答案。

错误消息是准确的。协议的要求是

func parseData<T: DataType>(_ data: Data, to: T.Type) throws -> T

但是您有一个实现的扩展

func parseData<T: Decodable & DataType>(_ data: Data, to: T.Type) throws -> T

即您的解析器只能解析Decodable的东西,但您的协议说它必须能够解析任何符合DataType的东西。


您可以使用 where 子句来指定更具体的要求

extension JSONParser {
func parseData<T: DataType>(_ data: Data, to: T.Type) throws -> T where T: Decodable {
try jsonDecoder.decode(T.self, from: data)
}
func parseData<T: DataType>(_ data: Data, to: T.Type) throws -> T {
throw CannotDecodeError
}
}

有一个函数需要获取任何类型的解析器来解析任何 可解析对象。

为什么不使用 Swift 内置的Decodable协议?它旨在为广泛的数据类别解决此问题。以下是它的假设:您可能想要解析的每种数据都属于以下类别之一:

  1. 表示单个基元值(如数字或字符串(的数据
  2. 表示对象集合的数据,其中每个对象都属于这三个类别之一
  3. 与 2 类似,但每个对象也有一个"键">

请注意,这些类别是递归的,因此这很自然地表示类似于 JSON 的东西,您可以在其中拥有一个包含包含字符串的对象的数组。

Swift 中的解码器(如 JSONDecoder(可以获取数据并尝试将其解释为这三个类别之一(特别是 SingleValueDecodingContainer、UnkeyedDecodingContainer 或 KeyedDecodingContainer(。

然后,一个可解码类知道如何采用这三个类别中的一个并实例化自己。

因此,只要您认为可以为使用一个或多个这些类别的所有可解析对象编写初始值设定项,您的对象就可以简单地符合内置的Decodable协议。

如果你想要一个自定义解析器,如ProtoBufParser,你所要做的就是告诉它如何通过实现Decoder协议来生成一个通用容器类型。

这就是允许您将任何类型的解析器与任何类型的可解析对象混合和匹配的方式。


*从技术上讲,可解码对象使用解码器本身来实例化自身。例如,这允许您在构造函数中尝试多种替代解码策略,直到某些工作正常。

最新更新