切换声明Fallthrough …应该允许吗?

只要我记得我已经避免使用switch语句。 其实,我不记得它曾经进入我的意识作为一种可能的方式来做事情,因为它早已钻入我的脑海,它只不过是在转换语句中的一个错误。 但是,今天我遇到了一些使用它的代码,这让我立刻想到社区中的每个人都认为转换语句是如何实现的。

是编程语言应该明确不允许的东西(就像C#那样,虽然它提供了一个解决方法),还是它是任何语言的一个特性,足以让程序员手中的东西离开呢?

编辑:我没有足够的具体到我的意思是通过。 我使用这种types很多:

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它将做切换语句中的一切。 我已经看过这个devise,我只是不知道我是否同意switch语句应该这样使用。 我认为第一个代码示例是非常有用和安全的。 第二个似乎有点危险。

这可能取决于你考虑的是什么。 我可以这样做:

 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; } 

但是,如果你有一个案例标签,然后是代码,通过另一个案例标签,我几乎总是认为这个邪恶。 也许将通用代码移到一个函数并从这两个地方调用将是一个更好的主意。

请注意,我使用C ++ FAQ定义的“邪恶”

这是一把双刃剑。 有时非常有用,往往是危险的。

什么时候好? 当你想要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 * /来表明你的意图。

根据你在做什么,贯彻是一件非常方便的事情。 考虑这种整洁和可以理解的方式来安排选项:

 switch ($someoption) { case 'a': case 'b': case 'c': // do something break; case 'd': case 'e': // do something else break; } 

想象一下用if / else来做这个。 这将是一个烂摊子。

你听说过达夫的装置吗? 这是使用切换贯穿的一个很好的例子。

这是一个可以使用的function,可以被滥用,就像几乎所有的语言function一样。

这可能是非常有用的几次,但一般来说,不会跌破是理想的行为。 应该允许穿透,但不是隐含的。

例如,更新某些数据的旧版本:

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

我喜欢用不同的开关回退语法,比如errr。

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

注意:如果你使用标志在枚举上声明了所有的情况,那么枚举已经可以实现了。 听起来也不那么糟糕,这些情况可能(应该)很好地成为你的枚举的一部分。

也许这将是一个很好的情况下(没有双关语意图)stream利的接口使用扩展方法? 就像,errr …

 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

至于任何事情:如果小心使用,它可以是一个优雅的工具。

然而,我认为这些弊端不仅仅是为了不使用它,而是最终不再允许它(C#)。 其中的问题是:

  • 很容易“忘记”rest
  • 对于代码维护者来说,并不总是显而易见的

善于使用开关/案例贯穿:

 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构造来重写,而完全没有任何损失。

我的最后一句话:远离掉落案例标签,就像在BAD的例子中一样,除非你在使用这个样式并且很好理解的地方维护遗留代码。

强大而危险。 突破的最大问题在于它并不明确。 例如,如果您遇到经常编辑的代码,并且具有切换function,那么您怎么知道这是故意的,而不是一个错误?

我使用它的任何地方,我确保它正确地评论:

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

我不喜欢我的switch语句通过 – 这是太容易出错,难以阅读。 唯一的例外是多个case语句都完全一样。

如果有一些通用代码需要使用switch语句的多个分支,那么我将它解压缩到一个可以在任何分支中调用的单独的通用函数中。

像你的第一个例子那样使用fall-through显然是好的,我不认为它是一个真正的失败。

第二个例子是危险的,(如果没有广泛评论)不明显。 我教导我的学生不要使用这样的结构,除非他们认为值得给它留下一个评论块,这就说明这是一个故意的失败,为什么这个解决scheme比替代scheme更好。 这阻止了马虎的使用,但仍然使它在被使用的情况下是有利的。

这与我们在太空项目中做的事情大致相同,因为有人想违反编码标准:他们不得不申请免除(我被要求就裁决提出build议)。

应该只在被用作代码块的跳转表时使用掉落思考。 如果代码的任何部分在更多的情况下有无条件的中断,那么所有的情况都应该以这种方式结束。 其他任何东西都是“邪恶的”。

在某些情况下,使用fall-throughs是程序员懒惰的行为 – 他们可以使用一系列的|| 报表,例如,而是使用一系列“全部”开关的情况。

这就是说,我发现他们是特别有用的,当我知道最终我会需要选项无论如何(例如在菜单响应),但还没有实现所有的select。 同样,如果你对“a”和“A”都进行了彻底的翻译,那么我发现使用switch if-through比复合if语句更清晰。

这可能是一个风格问题,程序员是怎么想的,但是我通常不喜欢以“安全”的名义去除一个语言的组成部分,这就是为什么我倾向于C及其变体/后裔的原因, Java的。 即使我没有“理由”,我也喜欢用指针之类的东西来绕圈。