为什么切换/大小写而不是如果/否则如果?

这个问题主要针对C / C ++,但我猜其他语言也是相关的。

我不明白为什么开关/大小写仍然被用来代替if / else if。 在我看来,就像使用goto's一样,结果是相同的混乱的代码,而同样的结果可以通过if / else if以更有组织的方式实现。

不过,我经常看到这些街区。 find它们的一个常见的地方是在一个消息循环(WndProc …)附近,而当它们引发最严重的破坏时,这些地方就是这样:variables在整个块中共享,即使不是主动的(也不可能是在里面初始化)。 必须特别注意不要突破,等等…

就个人而言,我避免使用它们,我想知道我错过了什么吗?

他们比if / else更有效率吗? 他们是否inheritance了传统?

总结我最初的文章和评论 – switch语句优于if / else语句有几个优点:

  1. 清洁代码。 代码与多个链接的if / else if ...看起来凌乱,难以维护 – switch结构更清洁。

  2. 性能。 对于高密度的case编译器生成跳转表,进行稀疏二分search或者一系列if / else ,所以在最坏的情况下, switchif / else一样快,但通常更快。 尽pipe一些编译器可以类似地优化if / else

  3. testing顺序无关紧要。 为了加速一系列的if / elsetesting,首先需要把更多可能的情况。 用switch / case程序员不需要考虑这个问题。

  4. 默认可以在任何地方。 有了if / else默认情况必须在最后 – 在最后一个之后。 在switchdefault可以在任何地方,程序员发现它更合适。

  5. 通用代码。 如果您需要为多个案例执行通用代码,您可能会忽略break并且执行会“落空” – 这是if / else无法实现的。 (对于这种情况,有一个很好的做法,就是发表一个特殊的评论/* FALLTHROUGH */ lint认可它,不会抱怨,如果没有这个评论,它会发出抱怨,因为这是常见错误而忘记了break )。

感谢所有评论者。

那么,一个原因是明确的….

如果你有一个开关/情况下,那么expression式不能改变….即

 switch (foo[bar][baz]) { case 'a': ... break; case 'b': ... break; } 

而用if / else,如果你写错了(或意图):

 if (foo[bar][baz] == 'a') { .... } else if (foo[bar][baz+1] == 'b') { .... } 

阅读你的代码的人会想知道“fooexpression应该是相同的”还是“为什么它们是不同的”?

请记住case / select提供了额外的灵活性:

  • 条件评估一次
  • 足够灵活,可以构buildDuff的设备
  • 贯彻落实(又名无中断)

以及它历史上执行得更快 (通过跳转/查找表)*

还要记住,switch语句允许继续控制stream,这允许您很好地组合条件,同时允许您为某些条件添加额外的代码,如下面的代码段所示:

 switch (dayOfWeek) { case MONDAY: garfieldUnhappy = true; case TUESDAY: case WEDNESDAY: case THURSDAY: case FRIDAY: weekDay = true; break; case SATURDAY: weekendJustStarted = true; case SUNDAY: weekendDay = true; break; } 

在这里使用if/else语句不会在任何地方变得很好。

 if (dayOfWeek == MONDAY) { garfieldUnhappy = true; } if (dayOfWeek == SATURDAY) { weekendJustStarted = true; } if (dayOfWeek == MONDAY || dayOfWeek == TUESDAY || dayOfWeek == WEDNESDAY || dayOfWeek == THURSDAY || dayOfWeek == FRIDAY) { weekDay = true; } else if (dayOfWeek == SATURDAY || dayOfWeek == SUNDAY) { weekendDay = true; } 

如果有很多情况,switch语句看起来更清晰。

当你有多个你想要的相同行为的值时,也是很好的 – 只要使用多个落到单个实现中的“case”语句就比if(this || that || someotherthing || .. 。)

它也可能取决于你的语言 – 例如,一些语言切换只能使用数字types,所以当你使用枚举值,数字常量等等时,它可以节省一些input。

 If (day == DAYOFWEEK_MONDAY) { //... } else if (day == DAYOFWEEK_TUESDAY) { //... } //etc... 

或稍微容易阅读…

 switch (day) { case DAYOFWEEK_MONDAY : //... case DAYOFWEEK_TUESDAY : //... //etc... } 

switch / case通常比if / else if / else更高效,但偶尔(取决于语言和编译器)转换为简单的if / else if / else语句。

我个人认为switch语句使得代码比一堆if语句更可读; 只要你遵循一些简单的规则。 规则你甚至应该遵循你的if / else if / else情况,但这又是我的意见。

这些规则:

  • 从来没有,你的交换机上有多条线路。 调用一个方法或函数,在那里做你的工作。
  • 始终检查是否中断/案例贯穿。
  • 冒泡例外。

明晰。 正如我在这里所说, else if有问题的线索是

ELSE IF的使用频率比语法所允许的要严格得多。 这是一个灵活的大锤,允许完全无关的条件进行testing。 但是,它通常用于扑灭CASE的苍蝇,比较相同的expression式与其他值…

这降低了代码的可读性。 由于结构允许有条件的复杂性,读者在parsingELSE IF时需要考虑更多的可能性,而不是parsingCASE。

实际上,一个switch语句意味着你正在处理的是一个或多或less的枚举,这个枚举给你一个即时的线索。

也就是说,任何一个OO语言的枚举开关都可能编码得更好 – 但是对于相同的值,一系列的if / else可能意味着相同的糟糕devise概率。

解决了交换机内部的所有东西都具有相同范围的担忧,您可以随时将您的案例逻辑放到另一个{}块中,像这样..

 switch( thing ) { case ONETHING: { int x; // local to the case! ... } break; case ANOTHERTHING: { int x; // a different x than the other one } break; } 

..现在我不是说这很漂亮。 只要把它放在那里就是可能的事情,如果你绝对不得不把事情隔离开来。

关于范围问题的另一个想法 – 似乎是一个很好的做法,只把一个开关放在一个函数中,而不是其他的。 在这种情况下,variables作用域并不是那么重要,因为这样你通常只能处理任何给定的函数调用的情况。

好的,最后一个想法是:如果一个函数包含多个开关,那么可能是重构代码的时候了。 如果一个函数包含嵌套的开关,这可能是重新思考你的devise的一个线索=)

可以肯定的是,它们编译的结果与If / ElseIf相同,但是当超过2或3个“elses”时,我发现Switch / Case更容易阅读。

switch case主要用来在编程时做出select。这与条件语句无关:

如果你的程序只需要做出select,那你为什么要使用if / else块,并增加编程工作量,同时又会降低程序的执行速度。

开关语句可以针对速度进行优化,但是如果案例值分散在大量的值上,则会占用更多的内存。

if / else通常很慢,因为每个值都需要检查。

Smalltalker可能会拒绝switch和if-then-else,并可能会写下如下内容:

 shortToLongDaysMap := Dictionary new. shortToLongDaysMap at: 'Mon' put: 'Monday'; at: 'Tue' put: 'Tuesday'; at: 'Wed' put: 'Wednesday' etc etc. longForm := shortToLongDaysMap at: shortForm ifAbsent: [shortForm] 

这是一个微不足道的例子,但我希望你能看到这种技术如何在大量的情况下扩展。

请注意at:IfAbsent:的第二个参数at:IfAbsent:与case语句的default子句相似。

这背后的主要原因是可维护性和可读性。 它很容易使代码更易于阅读和维护开关/ case语句,然后if / else。 因为你有很多if / else,那么代码变得像nest一样非常混乱,而且很难维护它。

还有一些执行时间是另一个原因。