Swift中开关盒的详尽状态

时间:2014-11-01 05:41:39

标签: ios swift

Apple documentation

  

每个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();
}

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

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

5 个答案:

答案 0 :(得分:61)

Swift仅在使用switch类型时才真正验证enum块是否详尽无遗。即使切换Bool,除了defaulttrue之外,还需要false块:

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

但是,使用enum,编译器很乐意只查看这两种情况:

enum MyBool {
    case True
    case False
}

var b = MyBool.True
switch b {
case .True:  println("true")
case .False: println("false")
}

如果您需要为编译器添加default块,但没有任何操作要做,break关键字就派上用场了:

var b = true
switch b {
case true:  println("true")
case false: println("false")
default: break
}

答案 1 :(得分:11)

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

更一般地说,编译器无法检测到整数值的穷举 - 即使您为每个整数值(case 0: ... case 1: ... ... case 65535:)添加特定情况,它也不知道您的开关是详尽的。 (理论上可以这样做:如果你想看到它,可以考虑filing a feature request。)

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

default

您可以将此规则概括为“如果类型系统知道您的类型的可能值,它可以检测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))") } 完整性”,但事实上类型系统不知道某个级别可能的(例如)switch值的范围是分裂的头发......

答案 2 :(得分:1)

迅速4.1。您需要指定所有情况,或者只在switch语句中包含默认块。

答案 3 :(得分:0)

(从Swift 4.2以及更早的版本开始):我有一个辅助函数,用于将UISegmentedControl分为2个段,将Bool?转换为selectedSegmentIndex。如果值为nil,则不应选择任何段。我的函数使用一个开关,该开关返回正确的段索引以获取true或false值,并使用该开关显式测试nil并满足编译器对其进行详尽穷举的需求:

case nil:  // only remaining possible value
    fallthrough
default:
    return UISegmentedControl.noSegment

从技术上讲,不需要case nil: fallthrough,因为default:就足够了,但是如果您想显式地测试一个值以使代码更加自我,则此语法可能很有用。 -记录文档,或者可能处于其他情况。

答案 4 :(得分:0)

检查您的枚举是否已初始化为可选,可以为case或nil