首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么UnkeyedDecodingContainer在解码时需要额外的外部数组?

为什么UnkeyedDecodingContainer在解码时需要额外的外部数组?
EN

Stack Overflow用户
提问于 2020-04-08 13:37:55
回答 1查看 1K关注 0票数 1

我正在尝试解码json文件中的正则表达式:

代码语言:javascript
复制
{
    ...
    "expressions" : [
        {"plus": [1, 2]},
        {"less": [{"plus": [3, 4]}, 5]}
    ],
    ...
}

我的目标是使用这种语法,以便尽可能清晰地输入这些语法。

最初,我使用了两个键控枚举,其中一个名为expressionDesc,可以是浮点数(.f1)、常量(.cnst)或操作(.op)。操作键的关联值为operatorDesc类型,这是第二个枚举。它包含操作符名称及其参数的表达式数组:

使用关键字枚举意味着我必须像这样输入json:

代码语言:javascript
复制
{
    ...
    "expressions" : [
        {"op": {"plus": [{"f1":1}, {"f1":2}]}},
        {"op": {"less": [{"op": {"plus": [{"f1":3}, {"f1":4}]}}, {"f1":5}]}}
    ],
    ...
}

这要难得多,所以我尝试使用UnkeyedDecodingContainer来避免键入表达式类型键,然后只根据给定的表达式类型解码:

代码语言:javascript
复制
enum operatorDesc : Decodable {
    case plus([expressionDesc])
    case less([expressionDesc])

    enum key: CodingKey { case plus; case less}
    enum CodingError: Error { case unknownFunction }

    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: key.self)
        do { let rawValue = try container.decode([expressionDesc].self, forKey: .plus); self = .plus(rawValue); print("Decoded \(self)") }
        catch { do { let rawValue = try container.decode([expressionDesc].self, forKey: .less); self = .less(rawValue); print("Decoded \(self)") }
                catch { throw CodingError.unknownFunction } }
    }
}

indirect enum expressionDesc : Decodable {
    case f1(f1)
    case const(String)
    case op(operatorDesc)
    init(from decoder: Decoder) throws {
        var container = try decoder.unkeyedContainer()
        do { let rawValue = try container.decode(Float.self); self = .f1(rawValue); print("Decoded \(self)") }
        catch { do { let rawValue = try container.decode(String.self); self = .const(rawValue); print("Decoded \(self)") }
                catch { do { let rawValue = try container.decode(operatorDesc.self); self = .op(rawValue); print("Decoded \(self)") }
                        catch {self = .f1(999); print("No expression found!") } } }
    }
}

struct sceneDesc : Decodable {
    ...
    let expressions : [expressionDesc]?
    ...
}

不幸的是,由于某种原因,这并没有完全实现我所期望的解码,并抛出了“预期的数组,得到了.”当我试图将表达式输入为顶级json格式时出现错误。但是,我在表达式周围添加了额外的数组:

代码语言:javascript
复制
{
    ...
    "expressions" : [
        [{"plus": [[1], [2]]}],
        [{"less": [[{"plus": [[3], [4]]}], [5]]}]
    ],
    ...
}

这确实是正确的解码,输出:

代码语言:javascript
复制
Decoded f1(1.0)
Decoded f1(2.0)
Decoded plus([Mobius.expressionDesc.f1(1.0), Mobius.expressionDesc.f1(2.0)])
Decoded op(Mobius.operatorDesc.plus([Mobius.expressionDesc.f1(1.0), Mobius.expressionDesc.f1(2.0)]))
Decoded f1(3.0)
Decoded f1(4.0)
Decoded plus([Mobius.expressionDesc.f1(3.0), Mobius.expressionDesc.f1(4.0)])
Decoded op(Mobius.operatorDesc.plus([Mobius.expressionDesc.f1(3.0), Mobius.expressionDesc.f1(4.0)]))
Decoded f1(5.0)
Decoded less([Mobius.expressionDesc.op(Mobius.operatorDesc.plus([Mobius.expressionDesc.f1(3.0), Mobius.expressionDesc.f1(4.0)])), Mobius.expressionDesc.f1(5.0)])
Decoded op(Mobius.operatorDesc.less([Mobius.expressionDesc.op(Mobius.operatorDesc.plus([Mobius.expressionDesc.f1(3.0), Mobius.expressionDesc.f1(4.0)])), Mobius.expressionDesc.f1(5.0)]))

所构造的最后表达式是:

代码语言:javascript
复制
Mobius.expressionDesc.op(Mobius.operatorDesc.plus([Mobius.expressionDesc.f1(1.0), Mobius.expressionDesc.f1(2.0)]))

Mobius.expressionDesc.op(Mobius.operatorDesc.less([Mobius.expressionDesc.op(Mobius.operatorDesc.plus([Mobius.expressionDesc.f1(3.0), Mobius.expressionDesc.f1(4.0)])), Mobius.expressionDesc.f1(5.0)]))

这是正确的。

我想知道的是,有什么方法可以避免json中每个表达式周围需要的额外数组[]来允许它解码吗?(这似乎只是在表达式枚举中使用UnkeyedDecodingContainer时才出现的)

而且,如果有人知道有更好的方法来达到我想要达到的目标,我会全神贯注--嵌套的do-捕获将变得非常丑陋,当我添加更多的操作时,从我所读到的内容来看,没有一种简单的方法可以解决这个问题。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2020-04-08 14:09:14

decoder.unkeyedContainer方法用于分析数组。对单个值分别使用decode.singleValueContainer是必要的:

代码语言:javascript
复制
indirect enum expressionDesc : Decodable {
    case f1(f1)
    case const(String)
    case op(operatorDesc)
    init(from decoder: Decoder) throws {
        let container = try decoder.singleValueContainer()
        do { let rawValue = try container.decode(Float.self); self = .f1(rawValue); print("Decoded \(self)") }
        catch { do { let rawValue = try container.decode(String.self); self = .const(rawValue); print("Decoded \(self)") }
                catch { do { let rawValue = try container.decode(operatorDesc.self); self = .op(rawValue); print("Decoded \(self)") }
                        catch {self = .f1(999); print("No expression found!") } } }
    }
}

我尝试了您的代码并首先解析了json,它运行得很好:

代码语言:javascript
复制
let text = """
{
    "expressions" : [
        {"plus": [1, 2]},
        {"less": [{"plus": [3, 4]}, 5]}
    ]
}
"""

print(try! JSONDecoder().decode(sceneDesc.self, from: text.data(using: .utf8)!))

结果:

(表达式: Optional([testapp.expressionDesc.op(testapp.operatorDesc.plus(testapp.expressionDesc.f1(1.0),testapp.expressionDesc.f1(2.0)),testapp.expressionDesc.op(testapp.operatorDesc.less([testapp.expressionDesc.op(testapp.operatorDesc.plus(testapp.expressionDesc.f1(3.0),testapp.expressionDesc.f1(4.0)),testapp.expressionDesc.f1(5.0)]))]))

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/61102045

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档