Switch语句掉线…应该允许吗?[关闭]


120

只要我记得我就避免使用switch语句掉线。实际上,我不记得它曾经作为一种可能的方式进入我的意识,因为它早在我的脑海中就被深深钻研了,它只不过是switch语句中的一个错误。但是,今天我遇到了一些设计上使用它的代码,这让我立即想知道社区中的每个人对switch语句失败的看法。

是某种编程语言应该明确不允许的(就像C#一样,尽管它提供了一种解决方法),或者它是任何一种功能强大的语言的功能,都足以让程序员掌握?

编辑: 我对落空的含义还不够具体。我经常使用这种类型:

    switch(m_loadAnimSubCt){
        case 0:
        case 1:
            // Do something
            break;
        case 2:
        case 3:
        case 4:
            // Do something
            break;
   }

但是,我担心这样的事情。

   switch(m_loadAnimSubCt){
        case 0:
        case 1:
            // Do something, but fall through to the other cases
            // after doing it.

        case 2:
        case 3:
        case 4:
            // Do something else.
            break;
   }

这样,只要大小写为0、1,它将在switch语句中执行所有操作。我从设计上就已经看到了这一点,但我不知道是否同意以这种方式使用switch语句。我认为第一个代码示例非常有用且安全。第二个似乎有点危险。



51
不赞成不具有建设性。关于这个问题的27票赞成表示还有其他人也有这种感觉。
Wes模式

2
“不具有建设性”是一个古老且模糊的封闭原因。如今,可以并且应该将此类问题标记为完全基于观点而关闭。SO是关于代码或设计的可回答问题,而不是“关于我对Feature X的看法的“社区”是什么(无论是什么)”。Programmers.SE会更适合,但即使到那时,这样一个广泛的,以观点为导向的问题的价值仍是高度可疑的。
underscore_d

1
有很明显的用例,其中使用了法线穿透,因此不确定为什么会基于意见。我同意这个问题有点不清楚,但是不应该因为没有建设性而被关闭。也许只是为了更清楚地说明以下情况而进行了编辑:“何时使用fallthrough?” 哪个有明确的答案。好的C ++文本解决了这个问题,这对于新的编码人员(甚至其他语言的经验丰富的编码人员)来说是令人困惑的,因此对于SO来说似乎是一个好问题。确实,这似乎是一个典型的 SO问题。即使要求的方式也不完美。
eric '18

Answers:


89

这可能取决于您认为的失败之处。我对这种事情还可以:

switch (value)
{
  case 0:
    result = ZERO_DIGIT;
    break;

  case 1:
  case 3:
  case 5:
  case 7:
  case 9:
     result = ODD_DIGIT;
     break;

  case 2:
  case 4:
  case 6:
  case 8:
     result = EVEN_DIGIT;
     break;
}

但是,如果您有一个case标签,后跟代码进入另一个case标签,那么我几乎总是认为这很糟糕。也许将通用代码移至函数并从两个地方调用将是一个更好的主意。

并且请注意,我使用“邪恶”C ++常见问题解答定义


我同意您的看法:我不认为您的示例是失败的,如果在某些情况下我想通过失败执行多个代码块,则可能会有更好的方法。
戴夫·杜普兰蒂斯

10
+1只是针对“邪恶”的定义。我会借用的,谢谢;-)
Joachim Sauer

我的意思是正确的,但您的榜样确实很糟糕。没人应该这样测试测试数字。Scnr,您的答案还是正确的。
蒂姆·布斯(TimBüthe)2010年

举例来说,这就是C#不允许的事情。可能出于某种原因:-)
乔伊(Joey)

可悲的是,对邪恶的定义似乎已经脱颖而出
HopefulHelpful

57

这是一把双刃剑。它有时非常有用,但通常很危险。

什么时候好?当您希望10个案件都以相同的方式处理时...

switch (c) {
  case 1:
  case 2:
            ... Do some of the work ...
            /* FALLTHROUGH */
  case 17:
            ... Do something ...
            break;
  case 5:
  case 43:
            ... Do something else ...
            break;
}

我喜欢的一条规则是,如果您想做任何想排除中断的事情,则需要明确注释/ * FALLTHROUGH * /以表明您的意图。


3
+1!我同意这有时是正确的答案,而我双重同意在设计时应予以评论。(在代码审查中,我让其他开发人员评论按设计的非空掉线。不是这样;我们是不支持的C#商店:)
John Rudy

4
我自己在适当的地方在代码中使用/ * FALL THROUGH * /注释。=]
斯特拉格

2
如果您使用PC-Lint,则必须插入/ *-fallthrough * /,否则会报错。
史蒂夫·梅利尼克诺夫

1
仍然,如果您想清楚表明这种行为是故意的,那么您也可以if(condition > 1 && condition <10) {condition = 1}; switch(...节省案例(为了使外观清晰),而且每个人都可以看到您确实希望这些案例触发相同的动作。
2014年

1
这仍然是糟糕的编码。第一种情况应调用一个函数,第二种情况应调用相同的函数,然后调用第二个函数。
BlueRaja-Danny Pflughoeft 2014年

21

您听说过达夫的装置吗?这是使用开关故障的一个很好的例子。

与几乎所有语言功能一样,它是可以使用且可以被滥用的功能。


每天学习新东西-谢谢!我确实为可怜的开发者感到遗憾,尽管他们经历了这种扭曲。
Justin R.

哇,这真是令人振奋。
福斯塔

6
注意达夫在那篇文章中引用的评论:“这段代码在辩论中形成了某种论点,但我不确定它是赞成还是反对。”
约翰·卡特

达夫的装置显然是邪恶的
Marjeta

21

根据您正在执行的操作,失败确实是一件方便的事情。考虑以下简洁明了的方式来安排选项:

switch ($someoption) {
  case 'a':
  case 'b':
  case 'c':
    // Do something
    break;

  case 'd':
  case 'e':
    // Do something else
    break;
}

想象一下使用if / else这样做。真是一团糟。


1
我发现这种类型的失败非常有帮助
Mitchel Sellers

如果“做某事”远不止是切换,那就不是“如果/否则”就是一团糟。使用if / else到处都可以清楚地测试哪个变量。即使在我眼中,这个小例子也不会看起来那么糟糕
grenix

10

几次它可能非常有用,但是一般而言,理想的行为是不会掉队。应该允许失败,但不能隐含。

一个示例,用于更新某些数据的旧版本:

switch (version) {
    case 1:
        // Update some stuff
    case 2:
        // Update more stuff
    case 3:
        // Update even more stuff
    case 4:
        // And so on
}

6

我希望为开关中的后备使用不同的语法,例如errr ..

switch(myParam)
{
  case 0 or 1 or 2:
    // Do something;
    break;
  case 3 or 4:
    // Do something else;
    break;
}

注意:如果您使用标志在枚举中声明所有情况,对枚举已经可以实现,对吗?听起来也不错。这些案例很可能已经(应该?)已经成为您枚举的一部分。

对于使用扩展方法的流畅接口来说,这可能是个好案例(无双关语)?有点像...

int value = 10;
value.Switch()
  .Case(() => { /* Do something; */ }, new {0, 1, 2})
  .Case(() => { /* Do something else */ } new {3, 4})
  .Default(() => { /* Do the default case; */ });

虽然那可能甚至更难读:P


1
我非常喜欢第一个建议。读取效果很好,并节省了几行代码。第二秒钟花了我一分钟的时间来缠住我的大脑,但是很有意义,但是看起来确实是一团糟。
福斯塔2009年

1
是的,这也是我的想法,这只是我放下的随意想法,目的是寻找使用现有语言结构进行切换的另一种方式。
Erik van Brakel,2009年

回答这个问题,我真的很喜欢!有一个关于如何提高其可读性的想法,但是SO不允许我发表多行评论:(有人应该像POC一样实现这一点,实现和使用起来看起来很有趣(:
Victor Elias

5

与任何事物一样:如果谨慎使用,它可能是一个优雅的工具。

但是,我认为这些弊端足以证明使用它,最终不再允许它(C#)。问题包括:

  • 忘记休息很容易
  • 对于代码维护者而言并非总是显而易见的是故意省略了中断

充分利用开关/外壳掉线:

switch (x)
{
case 1:
case 2:
case 3:
 Do something
 break;
}

Baaaaad使用交换机/案例掉线

switch (x)
{
case 1:
    Some code
case 2:
    Some more code
case 3:
    Even more code
    break;
}

我认为可以使用if / else构造来重写它,而不会造成任何损失。

我的最后一句话:避免在糟糕的示例中使用掉落式案例标签,除非您维护使用和理解这种样式的旧代码。


3
您可以使用if()和goto重新编写大多数语言结构,但这并不能证明放弃显式结构是合理的。
Shog9,

2
我知道,但是switch / case构造显式地使用“案例1:一些代码案例2:更多代码案例3:最终代码中断;” 可以并且应该使用if / else if重写(我认为)。
08年

1
请注意,切换可能比if-elses列表快许多倍。Switch使用跳转表,或者在不可能的情况下,其条件跳转将被构造在决策树中,而不是条件跳转的线性列表。结构良好的嵌套If-else语句充其量也将是最快的。
Jochem Kuijpers

4

它既强大又危险。失败的最大问题是它并不明确。例如,如果您遇到频繁编辑的代码,但这些代码带有切换功能,那么您如何知道这是故意的却不是错误?

无论在任何地方使用它,我都确保对其进行正确评论:

switch($var) {
    case 'first':
        // Fall-through
    case 'second':
        i++;
        break;
 }

2
如果没有案例“ first”的代码,则意图很明显。如果您在其中编写代码,并且还想运行案例“ second”的代码,则注释很重要。但是我还是会避免这种情况。
Joel Coehoorn

1
@Joel-我完全同意。在我的商店中,在这种情况下,我们让人们发表了详尽的评论,但我认为这样做会降低可读性。但是,如果那里有代码,请输入fallthrough注释。
弗雷德·拉森

我们的意思是“不明确”。这就是为什么我们休息;其他语言可以做到这一点。对于那些没有按顺序学习语言的人来说,这只是一个问题。C#要求使用默认情况下的ffs,没有理由恕我直言。
mckenzm

3

像在第一个示例中那样使用穿透功能显然是可以的,我认为这不是真正的穿透功能。

第二个示例很危险,并且(如果没有广泛评论)则很不明显。我教我的学生不要使用这样的构造,除非他们认为值得为它添加注释框,这说明这是一个故意的失败,以及为什么这种解决方案比替代方案更好的原因。这不鼓励随意使用,但在有利的情况下仍然允许使用。

当有人想违反编码标准时,这或多或少相当于我们在太空项目中所做的:他们必须申请豁免(我被要求就该裁决提供建议)。


2

我不喜欢自己的switch陈述-太容易出错并且很难阅读。唯一的例外是当多个case语句都执行完全相同的操作时。

如果某个switch语句的多个分支要使用某些通用代码,我会将其提取到一个单独的通用函数中,该函数可以在任何分支中调用。


1

在某些情况下,使用穿透是程序员的懒惰行为-他们可以使用一系列||。举例来说,这些语句使用一系列“全部捕获”切换用例。

话虽如此,当我知道最终我仍然需要这些选项(例如,在菜单响应中)但还没有实现所有选择时,我发现它们特别有用。同样,如果您同时对'a'和'A'进行穿透,则我发现使用开关穿透比使用复合if语句实质上更清洁。

这可能是风格和程序员的想法问题,但是我通常不喜欢以“安全”的名义删除语言的组成部分,这就是为什么我倾向于使用C及其变体/后代而不是说, Java。我喜欢能够与指针之类的东西相处,即使我没有“理由”。


严格来说。switch语句通过设置值跳到一堆特定的代码位置。尽管编译器很可能会发现此类问题,但在一系列or语句上,switch语句具有速度和正确性值。如果p为0或p为1或p为2。我实际上必须评估p是否为0和p为1,而不是跳转到代码中的p = 2位置。碰巧与p0和p1相同。但是,我不需要检查它们。

1

仅当将直通用作代码块的跳转表时,才应使用直通。如果在更多案例之前代码的任何部分都无条件中断,则所有案例组都应以这种方式结束。

其他都是“邪恶的”。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.