Закодируйте массив элементов, соответствующий протоколу Encodeable

Недавно я был удивлен, обнаружив следующее:

protocol A: Encodable {}

class B: A {
    var x = 3
}

class C: A {
    var y = 4
}

let items: [A] = [B()]
let encoded = try JSONEncoder().encode(items)

Сбой в Swift с:

Тип «любой A» не может соответствовать «Кодируемому».

пока это работает:

let items: [B] = [B()]
let encoded = try JSONEncoder().encode(items)

Видимо дело в том, что протоколы не соответствуют сами себе . Обходной путь представлен в этом ответе.

Я понимаю рассуждения и обходные пути в ответах, но это все равно довольно неудобно. Оба эти ответа датированы примерно 2017 годом; есть ли более чистый способ решить эту проблему в Swift 5?

Скажем так, у вас получится это сделать, но как вы тогда собираетесь его декодировать? У вас будет массив значений json, который может быть чем угодно, так как же вы можете написать для него код декодирования?

Joakim Danielson 05.04.2024 09:17

это хороший момент, и я думаю, что быстрый способ этого не сделает. В моем случае соответствующие классы идентифицируют себя с помощью атрибута типа. Это промежуточные выходные данные отладки, это не модель, которая сериализуется и десериализуется в одну и ту же модель, поэтому на самом деле это не проблема.

Amos Joshua 05.04.2024 11:59

Тем не менее, то, что что-то является кодируемым, не означает, что оно должно быть декодируемым, и наоборот. Я написал довольно много систем, которые являются однонаправленными в обоих направлениях. Нет ничего плохого в том, чтобы уметь кодировать [any Encodable]. Мы просто сейчас не можем. Сделать это возможным все еще включено в концептуальную дорожную карту (т. е. это не обещано, но желательно). Тем не менее, расшифровать [any Decodable] вряд ли когда-нибудь удастся. Здесь нет общего решения.

Rob Napier 05.04.2024 23:49
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
3
154
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

encode(_:) — это универсальный метод, который принимает конкретный статический тип, соответствующий Encodable. Общая конструкция метода является причиной того, что вы не можете использовать сам протокол. Компилятору необходимо знать структуру статического типа, чтобы иметь возможность синтезировать метод протокола encode(_:).

Закодируйте массив элементов, соответствующий протоколу Encodeable.

это нормально, но ты пытаешься

Закодируйте массив элементов по протоколу Encodeable.

что невозможно. Это действительно с 2017 года по сегодняшний день.

Спасибо, что нашли время ответить и указали на тонкие языковые различия — мне нравится акцент на том, чтобы быть протоколом кодирования, а не соответствовать ему. Я должен признать, что меня больше всего интересуют обходные пути... значит, обходной путь, описанный в другом билете, по-прежнему остается лучшим, что мы можем сделать?

Amos Joshua 05.04.2024 11:55
Ответ принят как подходящий

Пример обходного пути :)

struct AnyEncodable: Encodable {
    
    let item: any Encodable
    
    func encode(to encoder: any Encoder) throws {
        var container = encoder.singleValueContainer()
        try container.encode(self.item)
    }
}

let items: [A] = [B()]
let encoded = try JSONEncoder().encode(items.map { AnyEncodable(item: $0) })

Коротко и понятно - спасибо!

Amos Joshua 05.04.2024 12:09

Называть item.encode(to: encoder) не правильно, так как вы нарушите стратегии кодирования; вместо этого вам следует получить singleValueEncodingContainer() и закодировать в него значение. См. forums.swift.org/t/… и связанные темы для получения дополнительной информации.

Itai Ferber 05.04.2024 18:33

@ItaiFerber, ты прав. Я исправил свой ответ по вашему предложению. Спасибо за вашу бдительность

Adrian Bobrowski 05.04.2024 23:04

Обновление выглядит великолепно! Проголосовал за :)

Itai Ferber 06.04.2024 00:48

Другие вопросы по теме