在Swift 5枚举中使用@unknown default:如何抑制“Default will never be executed”警告?

21

假设我有一段现有的代码如下:

enum SomeEnumCases {
  case existing
  case alreadyExisting
}

func doSomething(withEnums enumCase: SomeEnumCases) {
  switch enumCase {
  case .existing:
    print("This case was already existing")
  case .alreadyExisting:
    print("This case was already existing too...")
  }
}

现在,如果我要添加一个新的枚举案例,上面的函数将显示编译错误,指出switch case必须是全面的,并且我将被强制处理新的缺失case。我可以在switch语句中添加第三个case,或添加默认语句。

现在,为了处理这种未预见的枚举情况,我想在上述现有函数中添加一个@unknown default case。唯一的问题是,现在它会给我一个警告,说Default will never be executed

所以问题是,如何使我的枚举具有未来可扩展性,使我可以:

  1. 详尽地处理所有当前的enum case,和
  2. 拥有一个未来未知case的默认处理机制,以及
  3. 仅在添加新的case并且这些case必须由default case处理时才会看到警告。

这意味着以下代码不应该产生警告:

enum SomeEnumCases {
  case existing
  case alreadyExisting
}

func doSomething(withEnums enumCase: SomeEnumCases) {
  switch enumCase {
  case .existing:
    print("This case was already existing")
  case .alreadyExisting:
    print("This case was already existing too...")
  @unknown default: // <-- warning: Default will never be executed: should be suppressed
    print("Alright, this is something new and exciting !!")
  }
}

但以下代码应该会发出警告:

enum SomeEnumCases {
  case existing
  case alreadyExisting
  case new
}

func doSomething(withEnums enumCase: SomeEnumCases) {
  switch enumCase { // <-- warning: Switch must be exhaustive: This should stay.
  case .existing:
    print("This case was already existing")
  case .alreadyExisting:
    print("This case was already existing too...")
  @unknown default:
    print("Alright, this is something new and exciting !!")
  }
}

那是否可以通过 @unknown 或其他方式实现呢?


与常规默认值一样,@unknown默认值匹配任何值;它是一个“万能”情况。但是,如果枚举的所有已知元素尚未被匹配,编译器将产生警告。为了更好地理解,请访问此链接:https://github.com/apple/swift-evolution/blob/master/proposals/0192-non-exhaustive-enums.md - sinner
1个回答

20
警告可能有点误导,因为规格说明已加重强调)如下所述:

非冻结枚举是一种特殊的枚举,即使在编译和发布应用程序之后,它也可能获得新的枚举案例。切换非冻结枚举需要额外的考虑。当库的作者将枚举标记为非冻结时,他们保留添加新枚举案例的权利,并且与该枚举交互的任何代码都必须能够处理这些未来的案例,而无需重新编译。只有标准库、Swift Apple框架的覆盖层以及C和Objective-C代码可以声明非冻结枚举。你在Swift中声明的枚举不能是非冻结的。

因此,这不仅仅是分支永远不会被执行,而是该功能完全不支持您定义的SomeEnumCases用户定义的Swift枚举。
在Swift 5中似乎没有支持的方法可以实现您所希望的操作,并且有一些迹象表明添加案例被视为破坏性更改,因为它可能会破坏二进制兼容性,但Swift是一个不断变化的目标...

这真是太遗憾了,因为这将使大多数开发人员不愿使用这个新案例。如果他们确实想要使用它,他们将不得不处理项目中永久警告的问题,显示“默认情况永远不会被执行”。如果您的项目中有许多枚举并且想要未来证明您的代码,那么这将变得难以承受,因为您最终将面临无数警告,而没有任何开发人员希望在其项目中出现这种情况。 - AdamM
2
@AdamM - 如果使用合适的“枚举”类型,就不会有警告,如果Swift编译器在使用错误类型时发出错误信息以避免混淆可能会更好。传统枚举是由一组文字值定义的类型,在C系语言中,这种类型是薄弱的,可以通过添加更多文字值来扩展。Swift使用的枚举类型本质上是一个“标记的不相交联合”,它们存在于许多语言中,并且可以在C系列中使用enumunionstruct组合构建。 [续...] - CRD
2
鉴于 Swift 目前编译枚举的方式,添加新的 case 可能会破坏现有已编译代码和 现有 case 之间的二进制兼容性,因此在添加任何新 case 时需要重新编译代码。这并不意味着 Swift 不能支持非冻结的 Swift 风格枚举,但他们(可能)权衡了利弊,并选择不这样做(但是 Swift 是一个不断发展的目标...)。 - CRD

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接