【问题标题】:Why use the switch statment instead of if else statments?为什么使用 switch 语句而不是 if else 语句?
【发布时间】:2010-02-02 15:47:33
【问题描述】:

开关似乎没用,因为它们可以用 if-else 语句代替,它可以做的不仅仅是匹配 char/int/enum 等。我只能想到一个开关的好用处,那就是用于解释命令行参数。

switch 语句有哪些实际用途?

【问题讨论】:

标签: language-agnostic switch-statement


【解决方案1】:

在某些情况下 switch 更具可读性并且派上用场。通常当您有一组选项时。

这是其中之一:

    int numDays = 0;
    int month = 2;
    int year = 2010;

    // find the number of days in the month
    switch (month) {
        case 1:
        case 3:
        case 5:
        case 7:
        case 8:
        case 10:
        case 12:
            numDays = 31;
            break;
        case 4:
        case 6:
        case 9:
        case 11:
            numDays = 30;
            break;
        case 2:
            if ( ((year % 4 == 0) && !(year % 100 == 0))
                 || (year % 400 == 0) )
                numDays = 29;
            else
                numDays = 28;
            break;
        default:
            System.out.println("Invalid month.");
            break;
    }

【讨论】:

  • 是的,我认为命令行选项也是如此。就像 -f 与 -F 类似,我们可以使用这种贯穿式概念。
  • @Kavon 这就是许多 C 程序处理开关参数的方式,在一段时间内使用 getopt() 并在名称上使用 switch()。
【解决方案2】:

在我看来,使用 switch 与 if/else 有两个原因:

  • 编译器可能能够更好地针对开关进行优化。
  • switch 语句更清楚地表达了代码的逻辑。具体来说,您根据某物的价值而不是更复杂的逻辑采用不同的分支的想法。到目前为止,这对我来说是更重要的原因。

【讨论】:

  • 我遇到了以下链接:blackwasp.co.uk/SpeedTestIfElseSwitch.aspx 这似乎支持您的优化论点(至少对于 .NET)。我也同意你的第二点。
  • +1 这种优化对于以递归下降方式处理消息的嵌入式代码尤其重要。但是,某些编译器仅在数值按顺序或与顺序无关时才应用查找表优化。
  • 我也喜欢 gcc 的扩展:switch (foo) { case 1 ... 10: doSomething();休息;案例 11 ... 200: doSomethingElse();休息; }
【解决方案3】:

您需要记住,开关更容易维护 - 一大堆嵌套的 if 和 else 很快就会变得难以维护。

开关可以更轻松地插入新的外壳。

【讨论】:

  • 对于嵌套的 if,switch 肯定更容易维护。因为 if/else-ifs(就像开关一样)和开关一样容易维护
【解决方案4】:

当我使用枚举来指示我的方法应该采取什么行动时,我会使用开关。当操作相互排斥时,它会有所帮助。

【讨论】:

    【解决方案5】:

    开关在多种语言中针对特定上下文进行了优化。通常,如果可能,他们会创建一个跳转表甚至哈希表。确实,当 可能 使用 switch 时,它很可能会比使用 if/else 的(逻辑上)相同的代码执行得更好。

    【讨论】:

      【解决方案6】:

      有很多情况,我们必须经常处理的一种情况是,如果您有很多选项,语法会更加压缩,有时比 if/then 语法更容易阅读。

      虽然可以对任何一种方式进行论证,但我发现开关在多个选项的情况下更易于阅读、维护和理解。我还在工厂模式类型的情况下使用过它,这有助于记录。

      【讨论】:

        【解决方案7】:

        如果我要比较多个值的同一个变量,我总是使用开关 - 开关比长 if-elseif 链更快地编写代码(并且更容易维护)。想象一下更改变量名称,使用 switch 将是一次编辑,使用 if-elseif 链将是多次。

        此外,根据您选择的语言,您可以使用“功能”的案例,而如果使用 if-elseif 链,您最终会得到重复的代码。

        【讨论】:

          【解决方案8】:

          switch 语句非常适合编写有限状态机,Click here to learn more about them

          【讨论】:

            【解决方案9】:

            这是使用语言的正确方法。它可以让编译器进行一些优化,并使代码更容易被不是你的人阅读。

            此外,在某些语言中,您可以切换枚举,如果您错过了值,编译器会发出警告(我认为)。

            【讨论】:

              【解决方案10】:

              你可以从 switch 语句中删除中断。这样你就可以拥有这个:

              CASE_A:
              ...
              BASE_B
              ...

              这样你就可以让 case_a 结合它下面的所有其他案例,直到它中断。仅使用 if 就没有那么好。

              【讨论】:

              • 这也很容易出错,当有人出现并且没有意识到代码的预期行为方式时。
              • 它偶尔有用,在这种情况下,它应该 /* 用大写字母注释以尝试让人们注意到缺少休息; */.
              • 另外,有些语言(我在想 C#)会强制你显式声明 fallthrough,否则 case 必须为空。
              【解决方案11】:

              几点:

              1. 某些语言允许您打开其他值类型,例如字符串(Coldfusion 的例子)
              2. switch 语句可能比一大堆 if/elseif/else 语句更容易阅读代码
              3. 在 switch 语句中,您可以在 case 结束时中断或允许代码继续处理语句中的其他 case。此功能使您可以轻松地建模一些 if/elseif/else 语句无法让您轻松完成的规则​​。
              4. 正如其他人所提到的,请记住编译器和引擎具有优化器,并且 switch 语句的优化方式不同。

              【讨论】:

                【解决方案12】:

                对于 Perl,使用 switch statement 可以显着降低代码的复杂性。

                只需比较这两个例子。

                • 使用given/when

                  use feature qw'switch';
                  my $num_days;
                  given( $month) {
                    when( [ 1,3,5,7,8,10,12 ] ){ $num_days = 31 }
                    when( [ 4,6,9,11 ] ){ $num_days = 30 }
                    when( 2 ){
                      $num_days = 29;
                      $num_days = 28 if     $year % 4;
                      $num_days = 28 unless $year % 100;
                      $num_days = 29 unless $year % 400;
                    default{ print "Invalid month.\n" }
                  }
                  
                • 使用for 替代新的~~ (smart-match) 运算符。

                  my $num_days;
                  for( 1,3,5,7,8,10,12 ){
                    if( $month == $_ ){
                      $num_days = 31;
                      last;
                    }
                  }
                  for( 4,6,9,11 ){
                    if( $month == $_ ){
                      $num_days = 30;
                      last;
                    }
                  }
                  if( $month == 2 ){
                    $num_days = 29;
                    $num_days = 28 if     $year % 4;
                    $num_days = 28 unless $year % 100;
                    $num_days = 29 unless $year % 400;
                  }
                  unless( defined $num_days ){
                    print "Invalid month.\n"
                  }
                  

                【讨论】:

                  【解决方案13】:

                  在我看来,开关的主要优点是它让读者立即明白所有选项都依赖于同一个变量。你当然可以编写一个 if/elseif/elseif 块来完成同样的事情,但是读者必须仔细检查它是否确实是每次测试的同一个变量。

                  还有一个噩梦般的维护场景,你在同一个变量上有一个很长的 if/elseif 并且有人决定更改变量名称,因此他更改了所有 if 的......除了他错过了一个。

                  正如其他人所指出的,还有一个事实是编译器通常可以更好地优化它。

                  【讨论】:

                    【解决方案14】:

                    Duff's Device。它在现代的实用性是值得商榷的,但它的威力却不是。

                    【讨论】:

                    • s/it's/its/g; (忽略这个括号:只需将评论填充到 15 个或更多字符)
                    • 哇!固定的。当人们滥用它/它时,我讨厌它......通常我对此非常擅长。对不起。
                    【解决方案15】:

                    它有助于提高可读性 - 乍一看,我知道应该运行哪个代码块的决定是基于同一变量的不同值。

                    【讨论】:

                      【解决方案16】:

                      可能编译器将 switch 语句转换为调度表比将等效的 if/else 汤转换为调度表更容易。如果(且仅当)这是真的,那么您应该将 O(1) 调度到相关代码,而不是 O(log n)(或 O(n),如果 if/else 汤写得不好)。

                      在某些(尽管不是全部)情况下,使用 switch 比使用 if/else 更容易检查您是否已涵盖必要的测试。

                      【讨论】:

                      • 问题是,在 O(n) 中运行的 if/else 汤更容易理解。
                      • 并非总是如此。看一下“一个月中的几天”的例子,我发现它和 if/else 结构一样可读。一个轻微的缺点是将具有相同天数的月份放在一个地方,而不是每个月都列出来增加。这样做仍然允许编译器使用跳转表,尽管它会(可能,取决于编译器的聪明程度)导致更大的代码大小。
                      【解决方案17】:

                      在大多数情况下,我更喜欢使用地图而不是开关。

                      if (actionMap.contains(choice)) {
                        Action a = actionMap.get(choice);
                        a.execute();
                      } else {
                        //do something else
                      }
                      

                      但在选择过于复杂而无法转换为地图的情况下,或者当可能采取多项操作时,切换会更好。

                      switch (choice) {
                        case 1: actionOne(); break;
                        case 2: if(actionOne()) {actionTwo()}; break; 
                        case 3: if(!actionOne() && (actionTwo() > 1)) {actionThree()}; result = 7;break; 
                        default: result = actionTwo();
                      }
                      

                      遗憾的是,有时要求很复杂。 Switch 在嵌套 if/else 构造的简化版本的情况下很有用。

                      【讨论】:

                        【解决方案18】:

                        不要问 Python 程序员这个问题,因为该语言没有 switch 语句,而是鼓励使用字典。

                        为了回答您的问题,我可以想到一个 switch 语句很有用的情况。 当语言/编译器/静态分析器可以确保您检查所有情况时,它很有用。这适用于枚举。

                        如果您将另一个项目添加到枚举中,您现在可以在您对这种枚举进行切换的所有位置收到警告,告诉您您缺少一个案例。

                        【讨论】:

                        • 我不认为这是一个优势,因为 else 链末尾的最终 else 块实现了同样的事情...... switch 不是 enum-比if 更友好。
                        猜你喜欢
                        • 2010-10-01
                        • 1970-01-01
                        • 1970-01-01
                        • 1970-01-01
                        • 2020-10-02
                        • 1970-01-01
                        • 1970-01-01
                        • 1970-01-01
                        • 1970-01-01
                        相关资源
                        最近更新 更多