golang 的失败似乎出乎意料
golang's fallthrough seems unexpected
我有以下代码:
package main
import (
"fmt"
)
func main() {
switch {
case 1 == 1:
fmt.Println("1 == 1")
fallthrough
case 2 == 1:
fmt.Println("2 == 1")
}
}
在 go playground 上打印两行 - see example here。我本来希望 fallthrough 语句包括对下一个 case
语句的评估,但事实并非如此。
当然,我总是可以使用一堆if
语句,所以这不是真正的障碍,但我很好奇这里的意图是什么,因为在我看来这不是-显而易见的结果。
有人愿意解释一下吗?例如:在 this 代码中,如何让第 1 和第 3 种情况执行?
A "fallthrough" statement transfers control to the first statement of the next case clause in an expression "switch" statement. It may be used only as the final non-empty statement in such a clause.
这似乎完美地描述了您观察到的行为。
据推测,Go 的 fallthrough 行为是模仿 C 的,它总是这样工作的。在 C 语言中,switch
语句只是条件 goto 链的简写,因此您的特定示例将被编译为 ,就好像 它写成这样:
# Pseudocode
if 1 == 1 goto alpha
if 2 == 1 goto beta
alpha:
fmt.Println("1 == 1")
beta:
fmt.Println("2 == 1")
如您所见,一旦执行进入 alpha
案例,它将继续向下流动,忽略 beta
标签(因为标签本身并没有真正做任何事情)。条件检查已经发生,不会再发生。
因此,fallthrough switch
语句的非直觉性仅仅是因为 switch
语句是薄薄的 goto 语句。
Switch 不是一堆如果。它更类似于 if {} else if {}
构造,但有一些曲折 - 即 break
和 fallthrough
。不可能让 switch 在第一种和第三种情况下执行 - switch 不会检查每个条件,它会找到第一个匹配项并执行它。就这些了。
它的主要目的是遍历可能值的列表并为每个值执行不同的代码。事实上,在C(switch语句的来源)中,switch表达式只能是整数类型,case值只能是常量,switch表达式也会进行比较。直到最近,语言才开始在 switch case 中添加对字符串、布尔表达式等的支持。
至于fallthrough逻辑,它也来自C。C中没有fallthrough运算符。在C中,除非遇到break运算符,否则执行将进入下一个case(不检查case值)。这种设计的原因是,有时您需要做一些特殊的事情,然后执行与另一种情况相同的步骤。因此,此设计仅允许这样做。不幸的是,它很少有用,所以默认情况下失败会在程序员忘记放入 break 语句时造成更多麻烦,然后在真正有意省略 break 时实际上会有所帮助。因此,许多现代语言将此逻辑更改为默认情况下永远不会失败,并且如果确实需要失败,则需要明确的失败声明。
不幸的是,很难想出一个非人为的 fallthrough 有用的例子,它足够短以适合答案。正如我所说,这种情况相对罕见。但有时你需要写类似这样的代码:
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")
}
我有以下代码:
package main
import (
"fmt"
)
func main() {
switch {
case 1 == 1:
fmt.Println("1 == 1")
fallthrough
case 2 == 1:
fmt.Println("2 == 1")
}
}
在 go playground 上打印两行 - see example here。我本来希望 fallthrough 语句包括对下一个 case
语句的评估,但事实并非如此。
当然,我总是可以使用一堆if
语句,所以这不是真正的障碍,但我很好奇这里的意图是什么,因为在我看来这不是-显而易见的结果。
有人愿意解释一下吗?例如:在 this 代码中,如何让第 1 和第 3 种情况执行?
A "fallthrough" statement transfers control to the first statement of the next case clause in an expression "switch" statement. It may be used only as the final non-empty statement in such a clause.
这似乎完美地描述了您观察到的行为。
据推测,Go 的 fallthrough 行为是模仿 C 的,它总是这样工作的。在 C 语言中,switch
语句只是条件 goto 链的简写,因此您的特定示例将被编译为 ,就好像 它写成这样:
# Pseudocode
if 1 == 1 goto alpha
if 2 == 1 goto beta
alpha:
fmt.Println("1 == 1")
beta:
fmt.Println("2 == 1")
如您所见,一旦执行进入 alpha
案例,它将继续向下流动,忽略 beta
标签(因为标签本身并没有真正做任何事情)。条件检查已经发生,不会再发生。
因此,fallthrough switch
语句的非直觉性仅仅是因为 switch
语句是薄薄的 goto 语句。
Switch 不是一堆如果。它更类似于 if {} else if {}
构造,但有一些曲折 - 即 break
和 fallthrough
。不可能让 switch 在第一种和第三种情况下执行 - switch 不会检查每个条件,它会找到第一个匹配项并执行它。就这些了。
它的主要目的是遍历可能值的列表并为每个值执行不同的代码。事实上,在C(switch语句的来源)中,switch表达式只能是整数类型,case值只能是常量,switch表达式也会进行比较。直到最近,语言才开始在 switch case 中添加对字符串、布尔表达式等的支持。
至于fallthrough逻辑,它也来自C。C中没有fallthrough运算符。在C中,除非遇到break运算符,否则执行将进入下一个case(不检查case值)。这种设计的原因是,有时您需要做一些特殊的事情,然后执行与另一种情况相同的步骤。因此,此设计仅允许这样做。不幸的是,它很少有用,所以默认情况下失败会在程序员忘记放入 break 语句时造成更多麻烦,然后在真正有意省略 break 时实际上会有所帮助。因此,许多现代语言将此逻辑更改为默认情况下永远不会失败,并且如果确实需要失败,则需要明确的失败声明。
不幸的是,很难想出一个非人为的 fallthrough 有用的例子,它足够短以适合答案。正如我所说,这种情况相对罕见。但有时你需要写类似这样的代码:
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")
}