KeyedDecodingContainer如何实现decode<T>(_ type: T.Type, forKey key: KeyedDecodingContainer<K>.Key) throws -> T where T: Decodable
How does KeyedDecodingContainer implement decode<T>(_ type: T.Type, forKey key: KeyedDecodingContainer<K>.Key) throws -> T where T: Decodable
我正在试验 Decodable,无法弄清楚编译器如何为特定的 Decodable
实例(例如 Book
)合成 decode(_ type: Decodable.Protocol, forKey key: CodingKey)
函数。
struct Book: Codable {
var title: String
var pages: Int
var author: String
var coauthor: String
}
struct Bookstore: Codable {
var book: Book
var owner: String
}
我试图自己编写一个 decode(_:forKey:)
函数,这样我就可以更好地了解编译器是如何综合它的,但我完全一头雾水。我开始为 Book.Type
重载 decode(_:forKey:)
函数,但就我所知。
extension KeyedDecodingContainer {
func decode(_ type: Book.Type, forKey key: CodingKey) throws -> Book {
print("I am about to decode a Book from the data keyed by \(key.stringValue)")
// I have no clue what to put here
}
}
如果有人能帮助我完成这个实现,我将不胜感激,因为它将帮助我更好地理解解码过程。
提前致谢!
编辑:
到目前为止我尝试过的:
extension KeyedDecodingContainer {
func decode(_ type: Book.Type, forKey key: CodingKey) throws -> Book {
print("I am about to decode a Book from the data keyed by \(key.stringValue)")
let decoder = try self.superDecoder(forKey: key as! K)
return try Book(from: decoder)
}
}
这行得通,但我不知道 as! K
到底在做什么,也不知道 superDecoder(forKey:)
做了什么。另外我不确定在这种情况下使用强制施法是否被认为是有风险的。有更安全的方法吗?
我认为你在这里误解了一些东西,编译器没有合成任何东西。 decode
是 泛型 ,泛型类型参数 T
被限制为 Decodable
。这意味着一旦它被声明,它将适用于所有符合 Decodable
的类型。没有为 Book
生成的单独实现。它们都是相同的实现,只是 T
不同。您应该关注的签名是:
func decode<T>(_ type: T.Type, forKey key: KeyedDecodingContainer<K>.Key) throws -> T where T : Decodable
它是如何实现的? source code 表示:
public func decode<T: Decodable>(
_ type: T.Type,
forKey key: Key
) throws -> T {
return try _box.decode(T.self, forKey: key)
}
所以一个问题,比如“如果必须的话,你会如何实施[这个方法]?”意义不大,因为方法已经实现了,不用自己实现了。
很明显,该实现对于理解其工作原理不是很有用。它只是将调用委托给其他东西。该调用最终被委托给 KeyedDecodingContainerProtocol
,即 KeyedDecodingContainerProtocol
的哪个实现取决于您使用的解码器。例如,JSONDecoder
将使用与 PropertyListDecoder
不同的解码容器。
现在问题来了,KeyedDecodingContainerProtocol
中的decode
方法是如何实现的?好吧,正如我们已经确定的那样,这取决于解码器。 JSON 解码器会做一些 JSON 特定的事情,而 属性 列表解码器会做一些 属性 列表特定的事情,但最终他们可能会调用 T.init(from:)
获取 T
的实例。 KeyedDecodingContainerProtocol.decode
是你可以自己实现的东西。如果您正在编写自己的解码器,则需要实现它。 T.init(from:)
如果您希望以自定义方式解码可编码对象,您也应该实现。
我找不到 JSONDecoder
的源代码,所以这里有一个开源 XML 解码器,您可以探索:https://github.com/ShawnMoore/XMLParsing
This is how they implemented KeyedDecodingContainerProtocol.decode
. This calls unbox
, which calls T.init(from:)
here.
我正在试验 Decodable,无法弄清楚编译器如何为特定的 Decodable
实例(例如 Book
)合成 decode(_ type: Decodable.Protocol, forKey key: CodingKey)
函数。
struct Book: Codable {
var title: String
var pages: Int
var author: String
var coauthor: String
}
struct Bookstore: Codable {
var book: Book
var owner: String
}
我试图自己编写一个 decode(_:forKey:)
函数,这样我就可以更好地了解编译器是如何综合它的,但我完全一头雾水。我开始为 Book.Type
重载 decode(_:forKey:)
函数,但就我所知。
extension KeyedDecodingContainer {
func decode(_ type: Book.Type, forKey key: CodingKey) throws -> Book {
print("I am about to decode a Book from the data keyed by \(key.stringValue)")
// I have no clue what to put here
}
}
如果有人能帮助我完成这个实现,我将不胜感激,因为它将帮助我更好地理解解码过程。
提前致谢!
编辑:
到目前为止我尝试过的:
extension KeyedDecodingContainer {
func decode(_ type: Book.Type, forKey key: CodingKey) throws -> Book {
print("I am about to decode a Book from the data keyed by \(key.stringValue)")
let decoder = try self.superDecoder(forKey: key as! K)
return try Book(from: decoder)
}
}
这行得通,但我不知道 as! K
到底在做什么,也不知道 superDecoder(forKey:)
做了什么。另外我不确定在这种情况下使用强制施法是否被认为是有风险的。有更安全的方法吗?
我认为你在这里误解了一些东西,编译器没有合成任何东西。 decode
是 泛型 ,泛型类型参数 T
被限制为 Decodable
。这意味着一旦它被声明,它将适用于所有符合 Decodable
的类型。没有为 Book
生成的单独实现。它们都是相同的实现,只是 T
不同。您应该关注的签名是:
func decode<T>(_ type: T.Type, forKey key: KeyedDecodingContainer<K>.Key) throws -> T where T : Decodable
它是如何实现的? source code 表示:
public func decode<T: Decodable>(
_ type: T.Type,
forKey key: Key
) throws -> T {
return try _box.decode(T.self, forKey: key)
}
所以一个问题,比如“如果必须的话,你会如何实施[这个方法]?”意义不大,因为方法已经实现了,不用自己实现了。
很明显,该实现对于理解其工作原理不是很有用。它只是将调用委托给其他东西。该调用最终被委托给 KeyedDecodingContainerProtocol
,即 KeyedDecodingContainerProtocol
的哪个实现取决于您使用的解码器。例如,JSONDecoder
将使用与 PropertyListDecoder
不同的解码容器。
现在问题来了,KeyedDecodingContainerProtocol
中的decode
方法是如何实现的?好吧,正如我们已经确定的那样,这取决于解码器。 JSON 解码器会做一些 JSON 特定的事情,而 属性 列表解码器会做一些 属性 列表特定的事情,但最终他们可能会调用 T.init(from:)
获取 T
的实例。 KeyedDecodingContainerProtocol.decode
是你可以自己实现的东西。如果您正在编写自己的解码器,则需要实现它。 T.init(from:)
如果您希望以自定义方式解码可编码对象,您也应该实现。
我找不到 JSONDecoder
的源代码,所以这里有一个开源 XML 解码器,您可以探索:https://github.com/ShawnMoore/XMLParsing
This is how they implemented KeyedDecodingContainerProtocol.decode
. This calls unbox
, which calls T.init(from:)
here.