首页 > 解决方案 > CodingKeys 一致性生成编译器错误

问题描述

我有一个DynamicKey符合CodingKey.. 的结构。然后我决定KeyedEncodingContainer用一个函数来扩展已经存在的功能来编码[String: Any]..

所以现在我进入了我的一致性部分,Struct Foo但我得到了一个编译器错误..

任何想法为什么编译器说它Foo.CodingKeys不符合CodingKeys当它继承自DynamicKey哪个具有一致性?

不工作代码:

struct DynamicKey: CodingKey, Equatable, ExpressibleByStringLiteral {
    var stringValue: String
    var intValue: Int? { return nil }

    init?(stringValue: String) {
        self.stringValue = stringValue
    }

    init?(intValue: Int) {
        return nil
    }

    //MARK:- Equatable Methods
    public static func == (lhs: DynamicKey, rhs: DynamicKey) -> Bool {
        return lhs.stringValue == rhs.stringValue
    }

    //MARK:- ExpressibleByStringLiteral Methods
    public init(stringLiteral value: String) {
        self.stringValue = value
    }

    public init(unicodeScalarLiteral value: String) {
        self.init(stringLiteral: value)
    }

    public init(extendedGraphemeClusterLiteral value: String) {
        self.init(stringLiteral: value)
    }
}

extension KeyedEncodingContainer where Key: CodingKey /*where Key == DynamicKey*/ {
    mutating func encodeDynamicValues(_ value: [String: Any], forKey key: Key) throws {
        //Other code here..
    }
}

struct Foo: Encodable {
    var arr: [String: Any]

    public func encode(to encoder: Encoder) throws {

        //Compiler Error: Instance method 'container(keyedBy:)' requires that 'Foo.CodingKeys' conform to 'CodingKey'
        //However, Foo.CodingKeys conforms to `CodingKey` because `DynamicKey` implements the protocol..
        var container = encoder.container(keyedBy: CodingKeys.self)



        try container.encodeDynamicValues(arr, forKey: .arr)
    }

    enum CodingKeys: DynamicKey {
        case arr
    }
}

但是,如果我更改DynamicKey为一个类,然后使用&运算符使枚举符合,编译器错误就会消失(没有&,它会给出相同的错误).. 为什么?

工作代码:

final class DynamicKey: CodingKey { //I don't need the equatable and expressible when it's a class so ignore that part.. adding it doesn't change anything..
    var stringValue: String
    var intValue: Int? { return nil }

    init?(stringValue: String) {
        self.stringValue = stringValue
    }

    init?(intValue: Int) {
        return nil
    }
}

extension KeyedEncodingContainer where Key: CodingKey /*where Key == DynamicKey*/ {
    mutating func encodeDynamicValues(_ value: Any, forKey key: Key) throws {
        //Other Code Here..
    }
}

struct Foo: Encodable {
    var arr: [String: Any]

    public func encode(to encoder: Encoder) throws {
        //CodingKeys now conforms to `CodingKey` because I made `DynamicKey` a class and used the `&` `CodingKey`
        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encodeDynamicValues(arr, forKey: .arr)
    }

    enum CodingKeys: DynamicKey & CodingKey {
        case arr
    }
}

标签: swiftswift4.2

解决方案


你的第一个例子

第一个示例中的问题只是您对这一行的理解问题:

enum CodingKeys: DynamicKey

你说:

任何想法为什么编译器说 Foo.CodingKeys 在继承自具有一致性的 DynamicKey 时不符合 CodingKeys ?

但是 Foo.CodingKeys 并没有“继承自 DynamicKey”。没有什么可以从结构“继承”。这里的符号与继承无关。您所做的是一个具有 DynamicKey 类型的原始值的枚举。(通常你无法做到这一点——原始值类型需要“可以用字符串、整数或浮点文字表示”,但你可以通过使 DynamicKey Equatable 和 ExpressibleByStringLiteral 来解决这个问题。)

这与您所说的语法相同:

enum MyEnum : Int {
    case myCase // zero
}

(您也对枚举使用神奇的名称 CodingKeys 感到困惑。但这可能并不直接相关。)


你的第二个例子

然后在您的第二个示例中,DynamicKey 是一个类,您会以完全相反的方式感到困惑。在这里,你做了一些完全不同的事情:

enum CodingKeys: DynamicKey & CodingKey {

在这里,您的枚举没有任何原始值类型;冒号后面的东西声明了协议限制。但是在这里您又以另一种方式欺骗了自己,因为实际上 DynamicKey 部分是无关紧要的;如果您简单地说,代码也可以编译

enum CodingKeys: CodingKey {

在该示例中真正发生的所有事情是,您已经要求自动综合符合 CodingKey,并且您已经得到了它。


推荐阅读