ios Swift 中 switch case 的穷举条件
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/26686542/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Exhaustive condition of switch case in Swift
提问by Girish Nair
The Apple documentationsays
苹果文档说
Every switch statement must be exhaustive. That is, every possible value of the type being considered must be matched by one of the switch cases.
每个 switch 语句都必须详尽无遗。也就是说,所考虑的类型的每个可能值都必须与其中一个 switch case 匹配。
So in new Xcode I have placed a code like this
所以在新的 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();
}
Now if i remove the default section I get a compiler error:
现在,如果我删除默认部分,则会收到编译器错误:
Switch must be exhaustive
Do you want to add missing cases? Fix
Switch 必须详尽无遗
您要添加缺失的案例吗?使固定
So my question is for a case that I have mentioned as case 0...65535:
have I not mentioned all the case values for an UInt16
?? But still I am getting an error ?? Why am I getting this error, Did i miss something ??
所以我的问题是针对我提到的一个案例,因为case 0...65535:
我没有提到UInt16
?? 但我仍然收到错误??为什么我会收到这个错误,我错过了什么吗??
回答by Nate Cook
Swift only truly verifies that a switch
block is exhaustive when working with enum
types. Even a switching on Bool
requires a default
block in addition to true
and false
:
Swift 仅switch
在处理enum
类型时真正验证块是否详尽。除了和之外,即使打开也Bool
需要一个default
块:true
false
var b = true
switch b {
case true: println("true")
case false: println("false")
}
// error: switch must be exhaustive, consider adding a default clause
With an enum
, however, the compiler is happy to only look at the two cases:
有enum
,但是,编译器很乐意只能看两种情况:
enum MyBool {
case True
case False
}
var b = MyBool.True
switch b {
case .True: println("true")
case .False: println("false")
}
If you need to include a default
block for the compiler's sake but don't have anything for it to do, the break
keyword comes in handy:
如果default
为了编译器需要包含一个块,但没有任何事情要做,break
关键字就派上用场了:
var b = true
switch b {
case true: println("true")
case false: println("false")
default: break
}
回答by rickster
Part of why you see that error because the compiler can't verify that switch is exhaustive without running code. The expression 0...65535
creates a ClosedInterval
struct, and when the switch statement executes it has to ask that struct if the value quantity
is in the interval. There's room for that to change at run time, so the compiler can't check it at compile time. (See the Halting Problem.)
您看到该错误的部分原因是编译器无法在不运行代码的情况下验证 switch 是否详尽。表达式0...65535
创建一个ClosedInterval
结构体,当 switch 语句执行时,它必须询问该结构体值quantity
是否在区间内。在运行时有改变的空间,所以编译器不能在编译时检查它。(参见停机问题。)
More generally, the compiler can't detect an exhaustive switch for integer values — even if you add specific cases for every integer value (case 0: ... case 1: ... ... case 65535:
), it doesn't know your switch is exhaustive. (Theoretically it could, though: consider filing a feature requestabout this if it's something you'd like to see.)
更一般地说,编译器无法检测到整数值的详尽开关——即使您为每个整数值 ( case 0: ... case 1: ... ... case 65535:
)添加特定情况,它也不知道您的开关是详尽的。(理论上它可以,但是:如果您想看到它,请考虑提交有关此的功能请求。)
As it stands, there are two scenarios where Swift can detect completeness and allow you to omit the default
clause: enums and value binding in tuples. @NateCook's answer covers enums — if you switch on an enum value and have a case
in your switch
for every case
in the enum, you don't need a default
. You also don't need a default
label if you switch on a tuple and bind every possible combination of values, as seen in the Swift book:
目前,有两种情况 Swift 可以检测完整性并允许您省略default
子句:枚举和元组中的值绑定。@NateCook 的回答涵盖了枚举——如果你打开一个枚举值并且case
在你的switch
for each 中都有一个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))")
}
You might generalize this rule as "if the type system knows about the possible values of your type, it can detect switch
completeness", but the fact that there's a level on which the type system doesn't know the range of possible (e.g.) UInt32
values is sort of splitting hairs...
您可以将此规则概括为“如果类型系统知道您的类型的可能值,它可以检测switch
完整性”,但事实上,类型系统在某个级别上不知道可能(例如)UInt32
值的范围有点分裂头发......
回答by Gurjinder Singh
Swift 4.1. Either you need to specify all cases or Just include default block inside switch statement.
斯威夫特 4.1。您需要指定所有情况或仅在 switch 语句中包含默认块。
回答by Kenster999
(As of Swift 4.2, and probably earlier): I have a helper function that converts a Bool?
into the selectedSegmentIndex
for a UISegmentedControl with 2 segments. If the value is nil
then neither segment should be selected. My function uses a switch, which returns the appropriate segment index for true or false values, and uses this to explicitly test for the nil
and satisfy the compiler's need for it to be exhaustive:
(从 Swift 4.2 开始,可能更早):我有一个辅助函数,可以将 aBool?
转换selectedSegmentIndex
为具有 2 个段的 UISegmentedControl 。如果该值不是,nil
则不应选择任何段。我的函数使用一个 switch,它返回 true 或 false 值的适当段索引,并使用它来显式测试nil
并满足编译器对其详尽无遗的需要:
case nil: // only remaining possible value
fallthrough
default:
return UISegmentedControl.noSegment
Technically, the case nil:
fallthrough
isn't required because the default:
will suffice, but this syntax may be useful if you want to explicitly test a value to make the code more self-documenting, or perhaps in another situation.
从技术上讲,这case nil:
fallthrough
不是必需的,因为default:
它就足够了,但是如果您想显式测试一个值以使代码更具自文档性,或者在其他情况下,此语法可能很有用。