golang的堕落似乎出人意料

时间:2017-07-23 18:42:05

标签: go switch-statement fall-through

我有以下代码:

package main

import (
    "fmt"
)

func main() {
    switch {
    case 1 == 1:
        fmt.Println("1 == 1")
        fallthrough
    case 2 == 1:
        fmt.Println("2 == 1")
    }
}

在go操场上打印两条线 - see example here。我本来期望通过声明来包括对下一个case声明的评估,但似乎并非如此。

当然,我总是可以使用一堆if语句,所以这不是一个真正的障碍,但我很好奇这里的目的是什么,因为在我看来这是一个非显而易见的结果

有人在乎解释吗?例如:在this代码中,如何执行第1和第3个案例?

3 个答案:

答案 0 :(得分:3)

来自language spec

  

“fallthrough”语句将控制转移到表达式“switch”语句中的下一个case子句的第一个语句。它只能用作这种子句中的最终非空语句。

这似乎完美地描述了你观察到的行为。

答案 1 :(得分:3)

据推测,Go的堕落行为是以C为模型的,C总是像这样工作。在C语言中,switch语句只是条件格式链的缩写,因此您的特定示例将被编译为,就好像它的编写方式一样:

    # Pseudocode
    if 1 == 1 goto alpha
    if 2 == 1 goto beta
alpha:
    fmt.Println("1 == 1")
beta:
    fmt.Println("2 == 1")

正如您所看到的,一旦执行进入alpha案例,它就会继续流下来,忽略beta标签(因为标签本身并没有真正做任何事情)。条件检查已经发生,并且不会再次发生。

因此,初级switch语句的非直观性质仅仅是因为switch语句是goto语句的简洁。

答案 2 :(得分:2)

Switch不是一堆ifs。它更类似于if {} else if {}构造,但有几个曲折 - 即breakfallthrough。切换不执行第一种和第三种情况是不可能的 - 交换机不会检查每个条件,它会找到第一个匹配并执行它。这就是全部。

它的主要目的是遍历可能值列表并为每个值执行不同的代码。事实上,在C(其中switch语句来自)中,switch表达式只能是整数类型,case case值只能是switch表达式也将被比较的常量。仅在最近才开始,语言开始在交换机情况下添加对字符串,布尔表达式等的支持。

关于通过逻辑,它也来自C.在C中没有穿透运算符。在C执行进入下一种情况(不检查大小写值),除非遇到break操作符。这种设计的原因是,有时您需要做一些特殊的事情,然后执行与其他情况相同的步骤。所以,这种设计只允许这样。不幸的是,它很少有用,所以默认情况下,当程序员忘记放入一个中断语句时会导致更多麻烦,然后实际上帮助真正省略故意破坏。因此,许多现代语言将此逻辑更改为默认情况下永远不会失败,并且如果实际需要掉线则需要明确的通过语句。

不幸的是,很难想出一个非常有用的堕落实例,它很短,足以适应答案。正如我所说,它相对罕见。但有时您需要编写类似于此的代码:

if x == a || x == b {
  if x == a {
    // do action a
  }
  // do action ab
} else if x == c {
   // do action c
} else if x == d {
  // do action d
}

事实上,我最近在一个项目中需要类似结构的代码。所以,我使用了switch语句。它看起来像这样:

switch x {
  case a: // do action a
          fallthrough
  case b: // do action ab
  case c: // do action c
  case d: // do action d
}

你从这个问题的转换在功能上等同于:

if 1 == 1 || 2 == 1 {
    if 1 == 1 {
        fmt.Println("1 == 1")
    }
    fmt.Println("2 == 1")
}