【问题标题】:Why the switch statement and not if-else?为什么是 switch 语句而不是 if-else?
【发布时间】:2010-10-01 17:55:00
【问题描述】:

我一直在想这个问题。到目前为止,我不是一个铁杆程序员,主要是小型 Python 脚本,并且我已经编写了几个分子动力学模拟。对于真正的问题:switch 语句 的意义何在?为什么不能只使用 if-else 语句

感谢您的回答,如果之前有人问过这个问题,请指向链接。

编辑

S.Lott 指出这可能与If/Else vs. Switch 的问题重复。如果你想关闭,那么就这样做。我将保留它以供进一步讨论。

【问题讨论】:

标签: if-statement language-agnostic switch-statement


【解决方案1】:

唯一可以更快的时间切换是当您的案例值是常量,不是动态的或以其他方式派生的,并且当案例的数量明显大于将哈希计算到查找表中的时间时。

在大多数引擎(包括 Chrome 的 V8 引擎)上编译为程序集以执行的 Javascript 的一个典型例子是 switch 语句在常见情况下的执行速度要慢 30%-60%:http://jsperf.com/switch-if-else/20

【讨论】:

  • 我已经告诉过你,我的基准测试设置为启用浏览器优化测试。所有其他测试都未经优化运行。是的,在未优化的代码中, elseif 更快。谁在乎?为什么我会关心未优化代码的速度?如果你在乎,那对我来说很好,但你应该这么说,因为大多数人不这样做。顺便说一句,原因是 benchmark.js 的作者故意有代码来尝试禁用优化,而不是因为你必须做一些神奇的事情来启用优化。
  • 对我来说,chrome 的速度快了 10 倍,这是怎么回事?未优化代码和优化代码之间的差异是如此之大,以至于如果您不了解编译器优化,您将无法解释这些差异而不听起来不真实。
  • “具有讽刺意味的是,我在获得 comp. sci 硕士学位的同时获得了编译器设计 A。” 在这里并不重要。重要的是是否进行了正确的性能测试(大量糟糕的测试并不意味着少数正确的测试)。
  • @AnthonyHildoer 是的,你是对的!做错 39 次测试是不可能的,尤其是对于像基准测试这样的东西,这非常容易,而且从历史上看,人们一直非常擅长
  • @AnthonyHildoer plover.net/~bonds/bdksucks.html 你犯了谬误谬误。
【解决方案2】:

switch 构造更容易转换为jump (or branch) table。当案例标签靠近时,这可以使 switch 语句比 if-else 更有效。这个想法是在内存中顺序放置一堆跳转指令,然后将值添加到程序计数器中。这用加法操作替换了一系列比较指令。

以下是一些极其简化的伪组装示例。一、if-else版本:

    // C version
    if (1 == value)
        function1();
    else if (2 == value)
        function2();
    else if (3 == value)
        function3();

    // assembly version
    compare value, 1
    jump if zero label1
    compare value, 2
    jump if zero label2
    compare value, 3
    jump if zero label3
label1:
    call function1
label2:
    call function2
label3:
    call function3

接下来是switch版本:

    // C version
    switch (value) {
    case 1: function1(); break;
    case 2: function2(); break;
    case 3: function3(); break;
    }

    // assembly version
    add program_counter, value
    call function1
    call function2
    call function3

您可以看到生成的汇编代码更加紧凑。请注意,需要以某种方式转换该值以处理 1、2 和 3 以外的其他值。但是,这应该说明这个概念。

【讨论】:

  • 您生成的汇编代码只有在您可以制作相同大小的案例时才有效。实际上,在添加之前 nop 填充和乘以值可以做类似的事情。但是,通常使用跳转表,在范围检查后获取“goto *table.124[value]”。
  • 而且在许多情况下,间接跳转比单次跳转要慢得多,因为间接分支的分支预测通常不太有效。
  • 很公平,我想保持简单。另外,我相信 C switch 语句早于分支预测,他想知道它为什么存在......
  • 在哪里不使用 switch 和使用 if else?
  • 这不取决于语言吗?有些允许的情况并不比你在 if 语句中看到的复杂(例如,正则表达式匹配字符串的情况)。
【解决方案3】:

我忽略了这种类型的低级优化,因为它通常不重要,并且可能因编译器而异。

我想说主要区别在于可读性。 if/else 非常灵活,但是当您看到一个开关时,您会立即知道所有测试都针对同一个表达式。

【讨论】:

    【解决方案4】:

    遍历几种情况的能力(故意省略 break 语句)可能很有用,而且正如一些人已经说过的那样,它也更快。不过,也许最重要和最不重要的考虑因素是,它只会使代码比 if/else 更漂亮。 :)

    【讨论】:

      【解决方案5】:

      除了提到的 .NET 中的其他代码可读性和优化之外,您还可以打开枚举等

      enum Color { Red, Green, Blue }; 
      
      Color c = Color.Red;
      
      switch (c) // Switch on the enum
      
      {
      
      // no casting and no need to understand what int value it is
      
      case Color.Red:    break;
      case Color.Green:  break;
      case Color.Blue:   break;
      
      }
      

      【讨论】:

        【解决方案6】:

        开关可以是optimized by compiler - 你会得到更快的代码。
        此外,我发现它在处理可枚举类型时更加优雅。

        总结 switch 语句为您提供性能 + 代码优雅 :)

        这里有一些有用的链接:

        【讨论】:

        • 我假设是 .net 世界,因为他正在链接到 C#
        • 例如 C++ 编译器做了一些有趣的优化
        • 代码示例中的 .sln 文件显示“#Visual C# Express 2008”
        • 代码优雅值得商榷。
        【解决方案7】:

        某些编译器可以“更好”地优化 Switch。在某些语言中使用 switch 语句存在缺陷。在 Java 中,switch 不能处理字符串,而在 VB2005 中,switch 语句不能用于单选按钮。
        Switch 可以更快更容易阅读,If-Then 更通用,可以在更多地方使用。

        【讨论】:

        • if-then 会在更多地方工作吗?试试这个 var sillyExample = true; switch (sillyExample) { case 3 > 2: console.log("lol");休息; case 0 !== 1: console.log("我猜它在这里断了"); } 实际上是 nvm
        【解决方案8】:

        为了表达性,switch/case语句允许你将多个case组合在一起,例如:

        case 1,2,3: do(this); break;
        case 4,5,6: do(that); break;
        

        为了性能,编译器有时可以将 switch 语句优化为跳转表。

        【讨论】: