CodingKeys 一致性会产生编译器错误
CodingKeys conformance generates a compiler error
我有一个结构 DynamicKey
符合 CodingKey
..
然后我决定将 KeyedEncodingContainer
的现有功能扩展为编码 [String: Any]
..
的功能
所以现在我进入 Struct Foo
中的一致性部分,但我遇到了编译器错误..
知道为什么编译器说 Foo.CodingKeys
在继承自具有一致性的 DynamicKey
时不符合 CodingKeys
吗?
无效代码:
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
更改为 class,然后使用 &
运算符使枚举符合,编译器错误就会消失(没有 &
, 会报同样的错误).. 为什么?
工作代码:
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
}
}
你的第一个例子
第一个例子中的问题只是你对这一行的理解问题:
enum CodingKeys: DynamicKey
你说:
Any ideas why the compiler says that Foo.CodingKeys does not conform to CodingKeys when it inherits from DynamicKey which has the conformance?
但是Foo.CodingKeys不是“继承自DynamicKey”。没有什么可以从结构“继承”。这里的符号与继承无关。您所做的是一个具有 DynamicKey 类型原始值的枚举。 (通常你不能这样做——原始值类型需要“可以用字符串、整数或浮点文字表示”,但你通过使 DynamicKey Equatable 和 ExpressibleByStringLiteral 解决了这个问题。)
它的语法与您所说的相同:
enum MyEnum : Int {
case myCase // zero
}
(您也对自己的枚举使用神奇的名称 CodingKeys 感到困惑。但这可能并不直接相关。)
你的第二个例子
那么在你的第二个例子中,DynamicKey 是 class,你会以完全相反的方式感到困惑。在这里,您做了完全不同的事情:
enum CodingKeys: DynamicKey & CodingKey {
在这里,您的枚举没有任何原始值类型;冒号后面的东西声明协议限制。但是在这里您又以另一种方式自欺欺人了,因为实际上 DynamicKey 部分是无关紧要的;如果你简单地说
,代码也能编译
enum CodingKeys: CodingKey {
该示例中真正发生的是您要求自动合成符合 CodingKey 的要求,并且您已经得到了它。
我有一个结构 DynamicKey
符合 CodingKey
..
然后我决定将 KeyedEncodingContainer
的现有功能扩展为编码 [String: Any]
..
所以现在我进入 Struct Foo
中的一致性部分,但我遇到了编译器错误..
知道为什么编译器说 Foo.CodingKeys
在继承自具有一致性的 DynamicKey
时不符合 CodingKeys
吗?
无效代码:
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
更改为 class,然后使用 &
运算符使枚举符合,编译器错误就会消失(没有 &
, 会报同样的错误).. 为什么?
工作代码:
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
}
}
你的第一个例子
第一个例子中的问题只是你对这一行的理解问题:
enum CodingKeys: DynamicKey
你说:
Any ideas why the compiler says that Foo.CodingKeys does not conform to CodingKeys when it inherits from DynamicKey which has the conformance?
但是Foo.CodingKeys不是“继承自DynamicKey”。没有什么可以从结构“继承”。这里的符号与继承无关。您所做的是一个具有 DynamicKey 类型原始值的枚举。 (通常你不能这样做——原始值类型需要“可以用字符串、整数或浮点文字表示”,但你通过使 DynamicKey Equatable 和 ExpressibleByStringLiteral 解决了这个问题。)
它的语法与您所说的相同:
enum MyEnum : Int {
case myCase // zero
}
(您也对自己的枚举使用神奇的名称 CodingKeys 感到困惑。但这可能并不直接相关。)
你的第二个例子
那么在你的第二个例子中,DynamicKey 是 class,你会以完全相反的方式感到困惑。在这里,您做了完全不同的事情:
enum CodingKeys: DynamicKey & CodingKey {
在这里,您的枚举没有任何原始值类型;冒号后面的东西声明协议限制。但是在这里您又以另一种方式自欺欺人了,因为实际上 DynamicKey 部分是无关紧要的;如果你简单地说
,代码也能编译enum CodingKeys: CodingKey {
该示例中真正发生的是您要求自动合成符合 CodingKey 的要求,并且您已经得到了它。