struct Person: Decodable {
let firstName: String
}
var data = """
{"firstName": "Fai"}
""".data(using: .utf8)!
let decoder = JSONDecoder()
let parsed = try decoder.decode(Person.self, from: data)
JSONDecoder
расшифрует данные, которые подтверждены Decodable
протоколом.
Поэтому я хочу знать, как быстро реализовать это. Но я не могу понять исходный код: https://github.com/apple/swift/blob/main/stdlib/public/core/Codable.swift
Протоколу Decodable
нужно только реализовать функцию init(from decoder: Decoder)
.
Если я собираюсь это сделать, я сделаю расширение для структуры:
extension struct: Decodable {
init(from decoder: Decoder) {...}
}
Но когда я удаляю Decodable на моем примере, компилятор выдает ошибки:
Метод экземпляра 'decode(_:from:)' требует, чтобы 'Person' соответствовал 'Decodable'
Так что это не быстрый способ реализовать это. Как быстрый путь? А где исходный код?
Просто для ясности: вы спрашиваете, как Swift реализует автоматический синтез init(from:)
, и как вы можете реализовать что-то подобное?
@Sweeper Да, я хочу знать, как swift это реализует, и я хочу извлечь из этого уроки.
Синтез соответствия Codable по умолчанию Встроен в компилятор: github.com/apple/swift/blob/main/lib/Sema/…
Вы можете увидеть, что компилятор пишет для вас, используя -print-ast
:
echo 'struct Person: Decodable {
let firstName: String
}' | swiftc -print-ast -
Это выведет большую часть автоматически сгенерированного кода (он должен включать все соответствия Codable, но есть несколько других видов автоматически сгенерированного кода, которые не будут включать их реализацию):
internal struct Person : Decodable {
internal let firstName: String
private enum CodingKeys : CodingKey {
case firstName
@_implements(Equatable, ==(_:_:)) fileprivate static func __derived_enum_equals(_ a: Person.CodingKeys, _ b: Person.CodingKeys) -> Bool {
private var index_a: Int
switch a {
case .firstName:
index_a = 0
}
private var index_b: Int
switch b {
case .firstName:
index_b = 0
}
return index_a == index_b
}
fileprivate func hash(into hasher: inout Hasher) {
private var discriminator: Int
switch self {
case .firstName:
discriminator = 0
}
hasher.combine(discriminator)
}
private init?(stringValue: String) {
switch stringValue {
case "firstName":
self = Person.CodingKeys.firstName
default:
return nil
}
}
private init?(intValue: Int) {
return nil
}
fileprivate var hashValue: Int {
get {
return _hashValue(for: self)
}
}
fileprivate var intValue: Int? {
get {
return nil
}
}
fileprivate var stringValue: String {
get {
switch self {
case .firstName:
return "firstName"
}
}
}
}
internal init(firstName: String)
internal init(from decoder: Decoder) throws {
@_hasInitialValue private let container: KeyedDecodingContainer<Person.CodingKeys> = try decoder.container(keyedBy: Person.CodingKeys.self)
self.firstName = try container.decode(String.self, forKey: Person.CodingKeys.firstName)
}
}
Для получения полной информации о реализации см. DerivedConformanceCodable.cpp . Вероятно, наибольший интерес к вашему вопросу представляет ️decodable_init.
Структура расширения?