在我的第一次代码评审中(不久前),有人告诉我,在所有switch语句中包含一个default子句是一种很好的实践。我最近想起了这个建议,但不记得理由是什么了。现在我听起来很奇怪。
是否有一个合理的理由总是包含默认语句? 这是语言依赖吗?我不记得当时我在用什么语言了——也许这适用于一些语言而不是其他语言?
在我的第一次代码评审中(不久前),有人告诉我,在所有switch语句中包含一个default子句是一种很好的实践。我最近想起了这个建议,但不记得理由是什么了。现在我听起来很奇怪。
是否有一个合理的理由总是包含默认语句? 这是语言依赖吗?我不记得当时我在用什么语言了——也许这适用于一些语言而不是其他语言?
当前回答
如果你知道switch语句只有一组严格定义的标签或值,那么就这样做,以覆盖基础,这样你总是会得到有效的结果。只需将默认值放在标签之上,从编程/逻辑上来说,它将是其他值的最佳处理程序。
switch(ResponseValue)
{
default:
case No:
return false;
case Yes;
return true;
}
其他回答
“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");
}
这取决于switch在特定语言中的工作方式,但是在大多数语言中,当没有匹配到case时,switch语句的执行就会毫无警告地结束。想象一下,你期望得到一组值,并在switch中处理它们,然而你在输入中得到了另一个值。什么都没发生,你也不知道什么都没发生。如果您发现了违约情况,您就会知道有问题。
我总是会使用默认子句,无论您使用哪种语言。
事情会出错,也确实会出错。价值观不会是你所期望的,等等。
不想包含默认子句意味着您确信自己知道可能的值集。如果你相信你知道这个可能值的集合,那么如果这个值在这个可能值的集合之外,你会想要知道它-这当然是一个错误。
这就是为什么你应该总是使用默认子句并抛出错误的原因,例如在Java中:
switch (myVar) {
case 1: ......; break;
case 2: ......; break;
default: throw new RuntimeException("unreachable");
}
除了“unreachable”字符串之外,没有理由包含更多信息;如果它真的发生了,无论如何您都需要查看源代码和变量的值等,异常堆栈跟踪将包括该行号,因此不需要浪费时间在异常消息中写入更多文本。
如果你知道switch语句只有一组严格定义的标签或值,那么就这样做,以覆盖基础,这样你总是会得到有效的结果。只需将默认值放在标签之上,从编程/逻辑上来说,它将是其他值的最佳处理程序。
switch(ResponseValue)
{
default:
case No:
return false;
case Yes;
return true;
}
一些(过时的)指南是这么说的,比如MISRA C:
最后一个默认子句的要求是防御性编程。该条款应采取适当的行动,或包含关于为什么不采取行动的适当评论。
这个建议已经过时了,因为它不是基于目前的相关标准。明显的疏漏是哈兰·卡斯勒说的
省略默认大小写允许编译器在看到未处理的大小写时选择性地发出警告或失败。静态可验证性毕竟比任何动态检查都要好,因此当您也需要动态检查时,这种牺牲是不值得的。
正如Harlan还演示的那样,在切换之后可以重新创建与默认情况相同的功能。当每个情况都是早期返回时,这是微不足道的。
从广义上讲,动态检查的典型需求是输入处理。如果一个值来自程序控制之外,它就不可信。
这也是Misra采取极端防御性编程立场的地方,即只要一个无效值在物理上是可表示的,就必须检查它,无论程序是否可证明是正确的。如果软件需要在出现硬件错误时尽可能地可靠,这是有意义的。但正如Ophir Yoktan所说,大多数软件最好不要“处理”错误。后一种做法有时被称为进攻性编程。