在我的第一次代码评审中(不久前),有人告诉我,在所有switch语句中包含一个default子句是一种很好的实践。我最近想起了这个建议,但不记得理由是什么了。现在我听起来很奇怪。
是否有一个合理的理由总是包含默认语句? 这是语言依赖吗?我不记得当时我在用什么语言了——也许这适用于一些语言而不是其他语言?
在我的第一次代码评审中(不久前),有人告诉我,在所有switch语句中包含一个default子句是一种很好的实践。我最近想起了这个建议,但不记得理由是什么了。现在我听起来很奇怪。
是否有一个合理的理由总是包含默认语句? 这是语言依赖吗?我不记得当时我在用什么语言了——也许这适用于一些语言而不是其他语言?
当前回答
No.
如果没有默认操作,那么上下文就很重要了。如果你只关心几个价值怎么办?
以读取游戏按键为例
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
只是浪费时间,毫无理由地增加了代码的复杂性。
其他回答
开关情况几乎总是有一个默认情况。
使用默认值的原因
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. 处理“默认”操作,其中的case是针对特殊行为的。
您在菜单驱动程序和bash shell脚本中经常看到这种情况。当变量声明在switch-case之外但没有初始化时,您也可能会看到这种情况,并且每个case初始化它为不同的东西。这里的默认值也需要初始化它,以便访问变量的代码不会引发错误。
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.
}
这是一个过于简化的例子,但关键是阅读代码的人不应该怀疑为什么变量不能是1或2以外的东西。
我能想到的唯一不使用默认值的情况是,当开关正在检查一些非常明显的东西时,其他选项都可以愉快地忽略
switch(keystroke)
{
case 'w':
// move up
case 'a':
// move left
case 's':
// move down
case 'd':
// move right
// no default really required here
}
如果switch语句中没有缺省情况,则在缺省情况下行为可能是不可预测的 在某个时间点出现,这在发展阶段是无法预测的。这是一个很好的练习 要包含默认大小写。
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解引用,内存泄漏以及其他类型的 严重的错误。
例如,我们假设每个条件初始化一个指针。但如果默认情况是 应该是上升的,如果我们不初始化这个例子,那么就完全有可能上升 一个空指针异常。因此,建议使用默认case语句,即使它 可能是微不足道的。
在我的公司,我们为航空电子设备和国防市场编写软件,我们总是包含一个默认语句,因为switch语句中的所有情况都必须显式处理(即使它只是一个说“什么都不做”的注释)。我们不能让软件只是行为不端,或者仅仅是在意外值(甚至是我们认为不可能的值)上崩溃。
可以讨论的是,默认情况并不总是必要的,但通过总是需要它,我们的代码分析人员很容易检查它。
至少在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;
}
}
虽然你可以在没有默认大小写的情况下避免上述方法的编译错误,只需要在最后添加一个return语句,但是提供默认大小写会使它更具可读性。
我相信这是特定于语言的,对于c++来说是枚举类类型的一个次要问题。这似乎比传统的C enum更安全。但
如果你看一下std::byte的实现,它是这样的:
enum class byte : unsigned char {} ;
来源:https://en.cppreference.com/w/cpp/language/enum
再想想这个:
否则,如果T是一个枚举类型,它的作用域是或 具有固定底层类型的无作用域,如果带括号的init-list具有 只有一个初始化式,如果从初始化式转换为 基础类型是非窄化的,如果初始化为 -直接列表初始化,然后使用 将初始化式转换为其基础类型的结果。 (因为c++ 17)
来源:https://en.cppreference.com/w/cpp/language/list_initialization
这是一个枚举类的例子,表示的值不是定义的枚举值。由于这个原因,您不能完全信任枚举。根据应用的不同,这一点可能很重要。
然而,我真的很喜欢@Harlan Kassler在他的帖子里说的话,我自己也会在某些情况下开始使用这个策略。
这是一个不安全枚举类的例子:
enum class Numbers : unsigned
{
One = 1u,
Two = 2u
};
int main()
{
Numbers zero{ 0u };
return 0;
}