Swift and Codable: кодируемая древовидная структура, заканчивающаяся значениями, которые подчиняются пользовательскому протоколу - PullRequest
1 голос
/ 15 апреля 2019

Я пытаюсь заставить древовидную структуру данных подчиняться кодируемому протоколу.Дерево заканчивается "неким объектом", который подчиняется протоколу "Терминал".Терминал расширяет Codable.

Каждый узел дерева представляет собой пару.У него есть ключ и значение.Значением является либо пара, либо терминал.

Есть две основные проблемы:

1) Я хотел бы, чтобы эта структура кодировалась в JSON, так что

class Pair: Codable {
   var key: String?
   var value: Codable?
}

let outputSimple = Pair(key: "a test key", value: "a test value")
// encodes to
// {"a test key": "a test value"}
// whereas currently encodes to
// {}

let outputComplex = Pair(key: "a parent", value: Pair(key: "another pair", value: "a test value"))
// encodes to
// {"a parent": {"another pair", "a test value"}}

РЕДАКТИРОВАТЬ: часть 2 может слегка запутать проблему,Чтобы прояснить проблему выше, если бы у меня было

class Pair: Codable {
   var key: String
   var value: String
}
let p = Pair(key:"foo", value: "bar")

, как я могу получить его для вывода {"foo": "bar"}, а не {key: foo, value: bar}?Я пытался

    override func encode(to encoder: Encoder) throws {
        var container = encoder.unkeyedContainer()
        container.encode(contentsOf: [key: value])
    }

, но получаю сообщение об ошибке "Метод экземпляра" кодировать (contentsOf :) "требует, чтобы" (ключ: _, значение: _) "соответствовал" Кодируемый ""

2) Я пытался сделать следующее, но это не сработало.Я получаю «Pair не соответствует протоколу Decodable»

protocol TreeNode: Codable {} 
struct Pair: TreeNode {
   var key: String?
   var value: TreeNode?
}

extension String: TreeNode {}

Это я могу обойти, сделав TreeNode классом, а Pair подклассом.Также вероятно, что это правильное поведение Свифта.Тем не менее, я задавался вопросом, могли ли бы другие пары глаз объяснить эту проблему.Я предполагал, что, пока я проверяю, что все значения относятся либо к паре типов, либо к чему-то еще, что подчиняется Codable, тогда это будет работать.

1 Ответ

3 голосов
/ 15 апреля 2019

Это не может работать.

value должен быть конкретным типом, соответствующим Codable, а не самим протоколом или вторым протоколом, соответствующим Codable

Что вы можете сделать, это объявить valueкак общий

class Pair<T: Codable>: Codable {
    var key: String?
    var value: T?

    init(key: String?, value: T?) {
        self.key = key
        self.value = value
    }
}

Может кодировать outputSimple и outputComplex

...