切换语句应该总是包含一个默认的子句?

在我的第一个代码评论之一(后来),我被告知,在所有switch语句中包含default子句是一个好习惯。 我最近记得这个build议,但不记得理由是什么。 我现在听起来很奇怪。

  1. 总是包含默认语句是否有明智的理由?

  2. 这个语言是依赖的吗? 我不记得我当时使用的语言 – 也许这适用于某些语言,而不适用于其他语言?

开关柜应该几乎总是有一个default情况。

使用default原因

1.“捕捉”一个意想不到的价值

 switch(type) { case 1: //something case 2: //something else default: // unknown type! based on the language, // there should probably be some error-handling // here, maybe an exception } 

2.处理“默认”行为,案件是特殊行为。

你可以在菜单驱动程序和bash shell脚本中看到很多。 当一个variables在switch-case之外被声明但是没有被初始化的时候,你也可能会看到这个,每个case初始化为不同的东西。 这里默认也需要初始化它,这样,访问variables的行代码就不会产生错误。

3.向某人展示您已阅读过您的代码的案例。

 variable = (variable == "value") ? 1 : 2; switch(variable) { case 1: // something case 2: // something else default: // will NOT execute because of the line preceding the switch. } 

这是一个过于简化的例子,但重要的是有人阅读代码不应该问为什么variable不能是1或2以外的东西。


唯一我能想到的不使用default是, 当交换机正在检查一些其他可以很好地忽略

 switch(keystroke) { case 'w': // move up case 'a': // move left case 's': // move down case 'd': // move right // no default really required here } 

无论您使用哪种语言,我都会使用默认条款。

事情会发生错误。 价值观将不会是你期望的,等等。

不想包含一个默认条款意味着你有信心,你知道一组可能的值。 如果你相信你知道一组可能的值,那么如果这个值超出了这个可能值的范围,你就会想知道它 – 这当然是一个错误。

这就是为什么你应该总是使用一个默认的子句,并抛出一个错误,例如在Java中:

 switch (myVar) { case 1: ......; break; case 2: ......; break; default: throw new RuntimeException("unreachable"); } 

没有理由包含更多的信息,而不仅仅是“无法访问”的string。 如果真的发生了,你将需要查看variables的来源和值等等,exception堆栈跟踪将包含该行号,所以不需要浪费时间在exception消息中写入更多的文本。

没有。

如果没有违约行为,情况很重要。 如果你只关心几个值呢?

以读一个游戏的按键为例

 switch(a) { case 'w': // Move Up break; case 's': // Move Down break; case 'a': // Move Left break; case 'd': // Move Right break; } 

添加:

 default: // Do nothing 

只是浪费时间,无缘无故地增加了代码的复杂性。

没有默认情况下,在某些情况下实际上可能是有益的。

如果你的开关情况是枚举值,没有默认情况下,你可以得到一个编译器警告,如果你缺less任何情况下。 这样,如果将来添加新的枚举值,并且忘记在交换机中添加这些值,您可以在编译时find问题。 您仍然应该确保代码对未处理的值采取适当的操作,以避免将无效的值转换为枚举types。 所以这可能最适合简单的情况下,你可以返回枚举的情况下,而不是中断。

 enum SomeEnum { ENUM_1, ENUM_2, // More ENUM values may be added in future }; int foo(SomeEnum value) { switch (value) { case ENUM_1: return 1; case ENUM_2: return 2; } // handle invalid values here return 0; } 

在我的公司,我们为航空电子和国防市场编写软件,而且我们总是包含一个默认语句,因为switch语句中的所有语句都必须被明确地处理(即使它只是一个说'无所事事'的语句)。 我们负担不起软件只是为了不当行为,或者仅仅是意外(甚至是我们认为不可能的)价值观的崩溃。

可以讨论的是,默认情况并不总是必要的,但总是要求它,我们的代码分析器很容易检查。

“switch”语句是否应该包含一个默认的子句? 不,它通常应该包括一个默认值。

包含一个默认的子句只有在需要时才有意义,比如声明一个错误条件或者提供一个默认的行为。 包括一个“只是因为”是货物崇拜的编程,并没有提供任何价值。 这就是所有“if”语句都应该包含“else”的“开关”。

这是一个无用的例子:

 void PrintSign(int i) { switch (Math.Sign(i)) { case 1: Console.Write("positive "); break; case -1: Console.Write("negative "); break; default: // useless } Console.Write("integer"); } 

这相当于:

 void PrintSign(int i) { int sgn = Math.Sign(i); if (sgn == 1) Console.Write("positive "); else if (sgn == -1) Console.Write("negative "); else // also useless { } Console.Write("integer"); } 

据我所知,答案是“默认”是可选的,说一个开关必须总是包含一个默认就像说每个“if-elseif”必须包含一个“其他”。 如果默认情况下有一个逻辑要完成,那么'default'语句应该在那里,否则代码可以继续执行而不做任何事情。

我要说这取决于语言,但是在C语言中,如果你打开一个枚举types,并且处理了每个可能的值,那么最好不要包括默认的情况。 这样,如果您稍后添加一个额外的枚举标记,并忘记将其添加到交换机,一个有能力的编译器会给你一个关于丢失的情况的警告。

有一个默认条款,当它不是真正需要的是防御性编程这通常会导致代码太复杂,因为太多的error handling代码。 这个error handling和检测代码会损害代码的可读性,使得维护变得更困难,并最终导致比解决更多的错误。

所以我相信,如果不应该达到默认值 – 你不必添加它。

请注意,“不应该达到”意味着,如果它到达它是软件中的错误 – 您需要testing可能包含不需要的值,因为用户input等。

如果你知道switch语句只会有一个严格定义的标签或值的集合,只要做到这一点覆盖的基础,这样你总是会得到有效的结果..只要把默认的编程/逻辑上的标签成为其他价值观的最佳处理者。

 switch(ResponseValue) { default: case No: return false; case Yes; return true; } 

至less在Java中不是强制性的。 根据JLS,它说最多可以有一个默认情况。 这意味着没有默认情况是可以接受的 它有时也取决于你使用switch语句的上下文。 例如在Java中,下面的开关块不需要默认情况

 private static void switch1(String name) { switch (name) { case "Monday": System.out.println("Monday"); break; case "Tuesday": System.out.println("Tuesday"); break; } } 

但是在下面的方法期望返回一个string,默认情况下来避免编译错误

  private static String switch2(String name) { switch (name) { case "Monday": System.out.println("Monday"); return name; case "Tuesday": System.out.println("Tuesday"); return name; default: return name; } } 

尽pipe你可以避免上面方法的编译错误,而不需要在最后有一个返回语句,但是提供默认情况下使得它更具可读性。

你应该有一个默认值来捕获不期望的值。

然而,我不同意阿德里安·史密斯(Adrian Smith)的意见,你的默认错误信息应该是完全没有意义的。 可能有一个你没有预见到的未处理的情况(哪种情况),你的用户最终会看到,像“无法访问”的消息是完全没有意义的,并没有帮助任何人在这种情况下。

举个例子,你有多less次完全没有意义的BSOD? 或者一个致命的exception@ 0x352FBB3C32342?

这是一个可选的编码“惯例”。 根据用途是否需要。 我个人认为,如果你不需要它,它不应该在那里。 为什么要包含用户不会使用或不能使用的内容?

如果案件的可能性是有限的(即布尔),那么默认的子句是多余的

如果switch语句中没有默认情况,那么如果在某个时间点出现这种情况,那么在开发阶段不可预测的行为可能是不可预测的。 包括一个default情况是一个很好的做法。

 switch ( x ){ case 0 : { - - - -} case 1 : { - - - -} } /* What happens if case 2 arises and there is a pointer * initialization to be made in the cases . In such a case , * we can end up with a NULL dereference */ 

这样的做法可能会导致像NULL解引用内存泄漏以及其他types的严重错误的错误

例如,我们假设每个条件初始化一个指针。 但是,如果default情况下应该出现,如果我们在这种情况下不初始化,那么就有可能出现空指针exception。 因此,build议使用default case语句,即使它可能是微不足道的。

因为MISRA C这样说:

最终违约条款的要求是防御性编程。 本条款应采取适当的行动或包含适当的评论为什么不采取行动。

这就是说,我build议不要在这个MISRA C上,对于大多数软件来说:

  • 这个防御性的编程风格指南并不关心只有一些值可能是有效的 – 如果variables是物理上能够接受一个值,即使这是一个错误,你应该处理它。 大多数软件应该更喜欢打印堆栈跟踪,而不是“处理”错误(如Ophir Yoktan所述)。
  • 特别是,Enum开关应该没有默认条款(如Harlan Kassler所说)。 而且,正如哈伦也非常明显地表明的那样,处理无效的价值观可以在交换之外完成 – 这在米斯拉的讨论中是没有的 。

取决于特定语言中的开关是如何工作的,然而在大多数语言中,当没有大小写匹配时,执行通过switch语句而没有警告。 想象一下,你期望一些值的集合,并在开关中处理它们,但是你在input中得到另一个值。 什么也没有发生,你不知道发生了什么。 如果你发现违约情况,你就会知道有什么问题。

如果开关值( 开关(variables ))不能达到默认情况,则不需要默认情况。 即使我们保持默认情况,它也不会被执行。 这是死码。

在枚举所使用的开关中可能不需要使用默认情况。 当交换机包含所有的值时,默认的情况将永远不会执行。 所以在这种情况下,这是没有必要的。

切换语句应该总是包含一个默认的子句? 在缺省情况下,没有开关情况可以存在,在开关情况下,默认情况下,在与其他任何情况下的值不匹配的情况下,触发开关值switch(x)