Swift:Switch语句的“fallthrough”行为

3

目前我有这个:

let somePoint = (1, 0)

switch somePoint {
case (0,0):
    print("origin") // does not print
    fallthrough
case (_, 0):
    print("y-axis") // prints y-axis. this makes sense
    fallthrough
case(0, _):
    print("x-axis") // prints x-axis (because of fallthrough? this should not print)
    fallthrough
case(-2...2, -2...2):
    print("in 5x5 box about the origin") // this prints and makes sense
default:
    print("somewhere else") // does not print
}

我希望通过这个switch语句,使每个case语句只有在为true时才被执行,而不是只有第一个匹配的case语句被执行。我认为我可以通过使用fallthrough语句来实现这一点。然而,这使我开始怀疑它的工作原理了。为什么fallthrough会自动执行下一行代码,即使它没有匹配的case语句?我该如何让这个switch语句按照我想要的方式运行呢?

2个回答

7
fallthrough会顺延到下一个case,而不是下一个匹配的case。这个概念来自于C语言中的switch语句,在该语句中,每个case可以被视为一个goto跳转标签,并且switch语句将执行带到第一个匹配的case
在C语言中,switch语句仅指定代码块内的执行起点。为了方便起见,您可以使用break语句来跳过switch体的其余部分,但没有任何强制要求;如果您不这样做,则执行会像case不存在一样正常继续执行。例如:
switch (countdown)
{
    case 3: puts("3...");
    case 2: puts("2...");
    case 1: puts("1...");
    case 0: puts("0!");
}

如果没有任何 break 语句,如果 countdown 是3,则会执行整个代码块(尽管 countdown 明显是3,而不是2、1或0)。
当执行从一个case转到另一个case时,而不是退出switch作用域(例如使用break语句),就会发生“fall through”现象(这就是Swift中fallthrough关键字的作用)。
在C中,您可以在switch语句中使用任意复杂结构,并重叠case。以下是合法的C程序:
switch (x)
{
    case 0:
        if (y == 3)
        {
    case 1:
            puts("hello");
        }
        else
        {
            puts("world");
        }

    case 2:
        puts("!");
}

这种用法非常罕见,通常很难理解(快!如果 x == 1,那么 else 分支会执行吗?)。我没有测试过,但如果你能用 Swift 做类似的事情,我会非常惊讶。
一般来说,在 C 中,穿透式的写法被认为是不好的风格,因为往往很难判断穿透是否是有意为之还是由于缺少 break 语句。Swift 使用 fallthrough 语句解决了这个问题,它明确表示您希望执行继续到 switch 语句内的下一个 case,而不是退出 switch 作用域。
在您的情况下,您不能使用 fallthrough 来实现您想要的效果,因为只有在需要线性执行序列时,才有用。您需要跳过无效的代码块,所以您需要使用 if-else 序列而不是 switch 语句。

在C#中,可以通过使用goto case X来解决这个问题,而无需使用新的关键字,易于阅读。 - phuclv
1
@LưuVĩnhPhúc,这是可能的,因为相对于Swift,C#(和C/C++/等)的情况(相对有限),并不是OP想要的。他们想要去另一个情况并开始寻找另一个匹配项。 C# goto case不会重新评估,因为选择条件不是动态的。换句话说,你已经知道你要去哪里了。 - paxdiablo

4
如果你想要跳到其他“匹配”情况而不是下一个情况(就像“fallthrough”所做的那样),那么“switch”不是正确的工具。 相反,你应该使用一系列的“if”语句,就像这样:
Bool gotOne = false;
if (somePoint.0 == 0 && somepoint.1 == 0) {
    print("origin")
    gotOne = true;
}
if (somepoint.1 == 0) {
    print("y-axis")
    gotOne = true;
}
if (somepoint.0 == 0) {
    print("x-axis")
    gotOne = true;
}
:
if (! gotOne) {
    print("somewhere else")
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接