66

这个问题主要指向 C/C++,但我想其他语言也很相关。

我不明白为什么仍然使用 switch/case 而不是 if/else if。在我看来,这很像使用 goto,并导致相同类型的混乱代码,而使用 if/else if 可以以更有条理的方式实现相同的结果。

尽管如此,我还是经常看到这些街区。找到它们的常见位置是在消息循环(WndProc...)附近,而这些是它们引发最严重破坏的地方之一:变量在整个块中共享,即使不合适(并且不能在里面初始化)。必须特别注意不要放弃休息,等等......

就个人而言,我避免使用它们,我想知道我是否遗漏了什么?

它们比 if/else 更有效率吗?它们是按照传统进行的吗?

4

15 回答 15

170

switch总结我最初的帖子和评论 -声明优于if/声明有几个优点else

  1. 更干净的代码。具有多个链接的代码if/else if ...看起来很杂乱且难以维护 -switch提供更清晰的结构。

  2. 表现。对于密集case值编译器生成跳转表,对于稀疏-二进制搜索或系列if/ else,所以在最坏的情况下与/switch一样快,但通常更快。尽管一些编译器可以类似地优化/ 。ifelseifelse

  3. 测试顺序无关紧要。为了加快一系列if/else测试,需要首先放置更多可能的案例。有了switch/case程序员就不需要考虑这个了。

  4. 默认值可以在任何地方。with if/ elsedefault 大小写必须在最后 - after last else。in switch-default可以在任何地方,只要程序员认为它更合适。

  5. 通用代码。如果您需要在几种情况下执行通用代码,您可以省略break并且执行将“失败” - 这是您无法使用if/实现的else。(有一个很好的做法是/* FALLTHROUGH */为这种情况添加一个特殊的注释——lint 识别它并且不会抱怨,没有这个注释它会抱怨,因为这是忘记的常见错误break)。

感谢所有评论者。

于 2009-06-22T17:30:07.463 回答
31

嗯,一个原因是清晰度....

如果你有一个开关/案例,那么表达式就不能改变....即

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

而使用 if/else,如果您写错(或故意):

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

阅读您的代码的人会想知道“ foo 表达式是否应该相同”,或者“为什么它们不同”?

于 2009-06-22T17:32:49.287 回答
17

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

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

于 2009-06-22T17:37:38.517 回答
13

还要记住 switch 语句允许控制流继续,它允许你很好地组合条件,同时允许你为某些条件添加额外的代码,比如下面的代码:

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;
}
于 2009-06-22T23:42:02.843 回答
10

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

当你有多个值并且你想要相同的行为时,这也很好 - 只使用多个“case”语句,这些语句落入单个实现比 if( this || that || someotherthing || .. . )

于 2009-06-22T17:35:37.863 回答
7

它还可能取决于您的语言——例如,某些语言切换仅适用于数字类型,因此当您使用枚举值、数字常量......等时,它可以为您节省一些输入。

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

或者更容易阅读......

switch (day) {
    case DAYOFWEEK_MONDAY :
        //...
    case DAYOFWEEK_TUESDAY :
        //...
    //etc...
}
于 2009-06-22T17:32:58.740 回答
4

switch/case 通常比 if/else if/else 更有效地优化,但偶尔(取决于语言和编译器)被翻译成简单的 if/else if/else 语句。

我个人认为 switch 语句使代码比一堆 if 语句更具可读性;只要您遵循一些简单的规则。即使对于 if/else if/else 情况,您也应该遵循规则,但这又是我的观点。

这些规则:

  • 永远不要在你的开关块上有超过一条线。调用一个方法或函数并在那里做你的工作。
  • 始终检查中断/案例失败。
  • 冒泡异常。
于 2009-06-22T17:29:23.067 回答
4

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

ELSE IF 的使用频率比语法所允许的要严格得多。这是一个灵活的大锤,允许测试完全不相关的条件。但它通常被用来拍打 CASE 的苍蝇,将相同的表达式与其他值进行比较......

这会降低代码的可读性。由于该结构允许条件复杂性的范围,因此读者在解析 ELSE IF 时需要记住比解析 CASE 时更多的可能性。

于 2009-06-22T17:40:20.947 回答
4

实际上,一个 switch 语句意味着您正在处理或多或少是一个枚举的东西,它可以让您立即了解正在发生的事情。

也就是说,在任何 OO 语言中打开枚举可能会更好地编码 - 并且在相同“枚举”样式值上的一系列 if/else 至少在传达意义方面同样糟糕,甚至更糟糕。

于 2009-06-22T17:46:44.933 回答
3

解决开关内的所有内容都具有等效范围的问题,您始终可以将案例逻辑放入另一个 { } 块中,就像这样..

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

..现在我不是说那很漂亮。如果您绝对必须将一种情况与另一种情况隔离开,那么只需将其作为可能的东西放在那里即可。

关于范围问题的另一种想法 - 只将一个开关放在一个函数中似乎是一种好习惯,而不是很多其他的。在这种情况下,变量作用域就不是那么重要了,因为这样你通常只处理对函数的任何给定调用的一种执行情况。

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

于 2009-06-25T00:18:42.413 回答
1

switch case主要用于在编程中进行选择。这与条件语句无关:

如果您的程序只需要做出选择,那么为什么要使用 if/else 块并增加编程工作量加上它会降低程序的执行速度。

于 2010-03-27T09:48:03.577 回答
0

if很确定它们编译成与/相同的东西else if,但我发现switch/超过 2 或 3秒case时更容易阅读。else

于 2009-06-22T17:29:10.803 回答
0

Switch 语句可以针对速度进行优化,但如果 case 值分布在大量值上,则会占用更多内存。

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

于 2009-06-22T17:32:47.897 回答
0

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]

这是一个简单的例子,但我希望你能看到这种技术如何适用于大量案例。

注意第二个参数 toat:IfAbsent:类似于 case 语句的默认子句。

于 2009-06-22T18:01:16.080 回答
0

这背后的主要原因是可维护性和可读性。使用 Switch/case 语句比 if/else 更容易使代码更具可读性和可维护性。因为你有很多 if/else,所以代码变得像嵌套一样混乱,并且很难维护它。

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

于 2010-08-03T11:53:03.343 回答