【问题标题】:Codable Enum with arguments and _ fails at compile time带有参数和 _ 的可编码枚举在编译时失败
【发布时间】:2021-12-26 22:29:52
【问题描述】:

我注意到我收到了一个非常确定的枚举类型的编译时错误。它可以通过以下方式复制:

enum ThisEnumCompiles {
    case stringArgument(_ string: String)
    case intArgument(_ int: Int)
}

enum ThisEnumAlsoCompiles: Codable {
    case stringArgument(string: String)
    case intArgument(int: Int)
}

enum ThisEnumDoesNot: Codable {
    case stringArgument(_ string: String)
    case intArgument(_ int: Int)
}

在您实际构建之前,XCode 中不会显示最后一个枚举的错误:

<unknown>:0: error: type 'ThisEnumDoesNot' has no member 'stringArgument(string:)'
<unknown>:0: error: type 'ThisEnumDoesNot' has no member 'intArgument(int:)'

我不清楚为什么添加 _ 会使最后一个枚举无法编译,而如果它不符合 Codable 则很好

【问题讨论】:

标签: ios swift swift5.5


【解决方案1】:

您可能希望针对这种enum 采用特定的Codable 策略。

这是一个例子:

enum MyEnum {
    case opt1(String)
    case opt2(Int)

}

extension MyEnum: Codable {
    private enum _Base: String, Codable {
         case option1
         case option2
     }

    private enum CodingKeys: String, CodingKey {
        case base
        case opt1Value
        case opt2Value
    }
    
    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        let b = try container.decode(_Base.self, forKey: .base)
        switch b {
        case .option1:
            let v = try container.decode(String.self, forKey: .opt1Value)
            self = .opt1(v)
        case .option2:
            let v = try container.decode(Int.self, forKey: .opt2Value)
            self = .opt2(v)
        }
    }
    
    func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        switch self {
        case .opt1(let v):
            try container.encode(_Base.option1, forKey: .base)
            try container.encode(v, forKey: .opt1Value)
        case .opt2(let v):
            try container.encode(_Base.option2, forKey: .base)
            try container.encode(v, forKey: .opt2Value)
        }
    }
    
}

我在这里做什么?我使用嵌套的_Base 枚举,默认为Codable(其原始值始终是一个字符串),它将在数据表示中表示要编码的枚举的 "base case"解码。 然后,我对与枚举的每个 "base case" 相关联的每种值使用不同的编码键来表示。 如果您最终决定更改枚举并为 Codable 实现添加/删除案例,编译器稍后将成为您的朋友。

编辑

您的问题具体指的是自动 Codable 合成 enum 与 Swift 5.5 版中的关联值(在此之前我们必须像我在这里那样编写它)。 那么在这种情况下,当您为关联值添加标签时,它将用作Codable 自动综合一致性中的编码键,另一方面,如果您没有_0,_1... 系列用作编码键。 因此这样做:

enum MyEnum: Codable {
    case opt1(_ string: String)
}

很可能会增加混乱,并且编译器无法在 ”_0” 和 ”string” 值之间选择它应该用作 CodingKeys 值。

【讨论】:

  • ` enum MyEnum { case opt1(string: String) case opt2(int: Int) } ` 在没有所有样板的情况下实现相同,不是吗?
  • 正如我在回答中已经提到的那样,这种方法还将在将来在编译时增强您的代码,以防您需要在枚举中添加/删除案例。
  • 在没有样板的情况下添加或删除案例会引发任何 switch 语句。无论如何,这并不能回答为什么简单地添加 _ 会改变行为的问题。
  • 可能导致隐式标注那些关联类型,编码键无法自动合成。
  • 还有一件事:也许您最好将此问题标记为特定于 Swift 5.5(或在某处说明其中一些示例只能编译采用 Swift 5.5)导致 自动 Codable 合成Swift 5.5 中添加了具有关联值的枚举。
猜你喜欢
  • 2013-05-07
  • 2012-10-06
  • 1970-01-01
  • 1970-01-01
  • 2015-03-13
  • 1970-01-01
  • 2023-03-26
  • 2018-04-07
  • 2016-02-28
相关资源
最近更新 更多