Swift中开关盒的详尽状态

Gir*_*air 27 ios swift

Apple 文档

每个switch语句都必须是详尽的.也就是说,所考虑类型的每个可能值必须与其中一个开关案例匹配.

所以在新的Xcode中我放置了这样的代码

println(UInt16.min); // Output : '0'
println(UInt16.max); // Output : '65535'

var quantity : UInt16 = 10;

switch quantity {
case 0...65535: //OR case UInt16.min...UInt16.max:
    println();
default:
    println();
}
Run Code Online (Sandbox Code Playgroud)

现在,如果我删除默认部分,我会收到编译错误,表明交换机必须是详尽的

所以我的问题是我提到的一个案例,因为case 0...65535:我没有提到所有的案例值UInt16?但我仍然得到一个错误?为什么我会收到这个错误,我错过了什么?

Nat*_*ook 67

Swift只能switch在使用enum类型时真正验证块是否详尽无遗.即使是开启,除了和之外还Bool需要一个default块:truefalse

var b = true
switch b {
case true:  println("true")
case false: println("false")
}
// error: switch must be exhaustive, consider adding a default clause
Run Code Online (Sandbox Code Playgroud)

enum,但是,编译器很乐意只能看两种情况:

enum MyBool {
    case True
    case False
}

var b = MyBool.True
switch b {
case .True:  println("true")
case .False: println("false")
}
Run Code Online (Sandbox Code Playgroud)

如果你需要default为编译器包含一个块但是没有任何东西可以做,那么break关键字就派上用场了:

var b = true
switch b {
case true:  println("true")
case false: println("false")
default: break
}
Run Code Online (Sandbox Code Playgroud)

  • 我刚刚用一个非可选的Bool来体验这个,并且认为我错过了一些东西.我提交了一份错误报告:19582311 (5认同)
  • 如果你有`true`和`false`的情况,`switch`不再需要`bool`的`default`.我不确定这个改变何时发生,但是在Xcode 7.3中使用Swift 2.2,上面的工作正常. (5认同)
  • @内特库克。刚刚在 xCode 10 上检查过,如果存在 true 和 false,则 Bool 不需要默认值。“错误:开关必须详尽无遗”不会出现 (2认同)
  • 确认的; 这个答案在 Swift 中不再适用。我怀疑从 Swift 2 或 3 开始。 (2认同)

ric*_*ter 11

部分原因是您看到该错误,因为编译器无法在不运行代码的情况下验证交换机是否详尽无遗.表达式0...65535创建一个ClosedInterval结构,当switch语句执行时,它必须询问该结构是否quantity在该区间内.在运行时有更改的空间,因此编译器无法在编译时检查它.(参见暂停问题.)

更一般地说,编译器无法检测到整数值的穷举开关 - 即使您为每个整数值(case 0: ... case 1: ... ... case 65535:)添加特定情况,它也不知道您的开关是详尽的.(从理论上讲,它可以:考虑提交一个关于此的功能请求,如果它是你想看的东西.)

目前,有两种情况可以让Swift检测完整性并允许您省略default子句:元组中的枚举和值绑定.@ NateCook的答案涵盖了枚举 - 如果你打开一个枚举值并且在枚举中有caseswitch的每一个case,你就不需要了default.default如果你打开一个元组并绑定每个可能的值组合,你也不需要一个标签,如Swift书中所示:

switch anotherPoint {
case (let x, 0):
    println("on the x-axis with an x value of \(x)")
case (0, let y):
    println("on the y-axis with a y value of \(y)")
case let (x, y):
    println("somewhere else at (\(x), \(y))")
}
Run Code Online (Sandbox Code Playgroud)

您可以将此规则概括为"如果类型系统知道您的类型的可能值,它可以检测switch完整性",但事实是类型系统不知道可能(例如)UInt32值的范围的级别是一种分裂的头发......