带返回的switch语句-代码正确性


90

假设我在C语言中的代码大致具有以下结构:

switch (something)
{
    case 0:
      return "blah";
      break;

    case 1:
    case 4:
      return "foo";
      break;

    case 2:
    case 3:
      return "bar";
      break;

    default:
      return "foobar";
      break;
}

现在显然,breaks对于代码正确运行不是必需的,但是如果我不把它们放在我的眼里,这似乎是一种不好的做法。

你怎么看?删除它们可以吗?还是保留它们以提高“正确性”?

Answers:


136

删除break语句。不需要它们,也许某些编译器会发出“无法访问的代码”警告。


2
其他无条件的控制跳转语句也是如此,例如continueor goto,使用它们代替break
caf 2010年

31

我会采取完全不同的方法。不要在方法/函数中间返回。取而代之的是,只需将返回值放在本地变量中,然后将其发送出去。

我个人认为以下内容更具可读性:

String result = "";

switch (something) {
case 0:
  result = "blah";
  break;
case 1:
  result = "foo";
  break;
}

return result;

23
在C语言中,“一次退出”理念是有意义的,您需要确保正确清理所有内容。考虑到在C ++中,您可能会在任何时候因异常而脱离该函数,一个退出原理在C ++中并不是真正有用。
Billy ONeal 2010年

29
从理论上讲,这是一个好主意,但是它经常需要额外的控制块,这会影响可读性。
mikerobi 2010年

8
我这样做的主要原因是,在较长的函数中,通过代码扫描时很容易错过退出向量。但是,当出口始终在尽头时,可以更轻松地快速掌握发生的情况。
NotMe 2010年

7
好吧,代码中间的return块让我想起了GOTO滥用。
NotMe 2010年

5
@Chris:在更长的函数中,我完全同意-但这通常会带来更大的问题,因此请将其重构。在许多情况下,这是在开关上返回的琐碎函数,而且很清楚应该发生什么,因此不要在跟踪额外变量时浪费脑力。
斯蒂芬2010年

8

我个人将删除退货并保留休息时间。我将使用switch语句将值分配给变量。然后在switch语句之后返回该变量。

尽管这是一个有争议的观点,但我一直觉得良好的设计和封装意味着一种进出的方式。保证逻辑容易得多,并且不会因函数的循环复杂性而意外丢失清除代码。

一个例外:如果在函数开始时检测到错误的参数(在获取任何资源之前),则尽早返回是可以的。


可能对此特别有益switch,但不一定总的来说最好。好吧,可以说一个函数内部的switch语句位于另外500行代码的前面,该代码仅在某些情况下才有效true。对于不需要执行所有多余代码的情况,这有什么意义?对于那些s 来说,只return在里面更好吗?switchcase
Fr0zenFyr19年

6

保持中断-如果/如果中断已经存在,以后再编辑代码时,您不太可能遇到麻烦。

话虽如此,许多人(包括我)都认为从函数中间返回是一种不好的做法。理想情况下,一个功能应具有一个入口点和一个出口点。


5

删除它们。从case语句返回是很习惯的,否则就是“无法到达的代码”的噪音。


5

我会删除它们。在我的书中,应将这样的无效代码视为错误,因为它会使您重复一遍,并问自己:“我将如何执行该行?”


4

我通常会在没有它们的情况下编写代码。国际海事组织,死代码往往表明草率和/或缺乏理解。

当然,我也会考虑类似:

char const *rets[] = {"blah", "foo", "bar"};

return rets[something];

编辑:即使编辑了帖子,此总体思路也可以正常工作:

char const *rets[] = { "blah", "foo", "bar", "bar", "foo"};

if ((unsigned)something < 5)
    return rets[something]
return "foobar";

在某些时候,特别是如果输入值稀疏(例如1、100、1000和10000),则需要稀疏数组。您可以很好地将其实现为树或地图(尽管在这种情况下当然仍然可以使用开关)。


编辑帖子以反映为什么此解决方案无法正常工作。
houbysoft 2010年

@your edit:是的,但是会占用更多的内存,等等。恕我直言,切换是最简单的方法,这就是我想要的这么小的功能(它只是切换)。
houbysoft 2010年

3
@houbysoft:在断定它会占用更多内存之前,请仔细查看。对于典型的编译器,两次使用“ foo”(例如)将使用两个指向单个数据块的指针,而不是复制数据。您也可以期望使用较短的代码。除非您有很多重复的值,否则通常会节省总体内存。
杰里·科芬

真正。我仍然坚持我的解决方案,因为值列表很长,而且开关看起来更好。
houbysoft 2010年

1
确实,当开关值是连续的并且数据类型是同质的时,对于这样的问题,更优雅,更有效的答案是使用数组来完全避免开关。
Dwayne Robinson

2

我会说删除它们并定义一个默认值:分支。


如果没有合理的默认值,则不应定义默认值。
Billy ONeal 2010年

有一个,我定义了一个,我只是没有把它放在问题中,而是现在编辑它。
houbysoft 2010年

2

拥有一个数组会不会更好

arr[0] = "blah"
arr[1] = "foo"
arr[2] = "bar"

而且return arr[something];呢?

如果是关于常规的实践,则应将break语句保留在开关中。如果您return将来不需要语句,则可以减少它进入下一个语句的机会case


编辑帖子以反映为什么此解决方案无法正常工作。
houbysoft 2010年

2

对于“正确性”,单入口,单出口块是一个好主意。至少在我获得计算机科学学位的时候。所以我可能会声明一个变量,在开关中分配给它,然后在函数末尾返回一次


2

你怎么看?删除它们可以吗?还是保留它们以提高“正确性”?

删除它们很好。使用return正是其中的场景 break不应该使用。


1

有趣。这些答案大多数的共识似乎是,多余的break陈述是不必要的混乱。另一方面,我break将开关中的语句作为案件的“结案”来阅读。由于潜在的漏洞case而不会break消失的情况下,不会以失败而告终的块会趋向于我。

我知道这不是用a return而不是a时的情况break,而是我的眼睛“看”开关中的表壳,因此我个人更希望将每个表头case都与a配对break。但是许多编译器不抱怨的break后一个return是多余的/不可达,显然我似乎是少数反正。

所以摆脱break以下return

注意:所有这些都忽略了违反单一出入境规则是否是一个好主意。就目前而言,我认为不幸的是会根据情况而改变...


0

我说删除它们。如果您的代码太不可读,以至于需要“为了安全起见”就必须坚持一下,那么您应该重新考虑您的编码风格:)

同样,我也一直不希望在switch语句中混合使用中断和返回,而是坚持使用其中之一。


0

我个人倾向于丢失breaks。这种习惯的一个来源可能来自Windows应用程序的编程窗口过程:

LRESULT WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch (uMsg)
    {
        case WM_SIZE:
            return sizeHandler (...);
        case WM_DESTROY:
            return destroyHandler (...);
        ...
    }

    return DefWindowProc(hwnd, uMsg, wParam, lParam);
}

我个人认为此方法比声明每个处理程序设置的返回变量然后在最后将其返回要简单,简洁和灵活得多。使用这种方法,breaks是多余的,因此应该继续使用-它们没有用(语法上或IMO上没有用),只会使代码膨胀。


0

我认为*突破 * s是有目的的。这是为了保持编程的“意识形态”。如果我们只是在没有逻辑一致性的情况下对代码进行“编程”,那么您现在就可以阅读,但是明天再试。尝试向老板解释。尝试在Windows 3030上运行它。

Bleah,这个想法很简单:


Switch ( Algorithm )
{

 case 1:
 {
   Call_911;
   Jump;
 }**break**;
 case 2:
 {
   Call Samantha_28;
   Forget;
 }**break**;
 case 3:
 {
   Call it_a_day;
 }**break**;

Return thinkAboutIt?1:return 0;

void Samantha_28(int oBed)
{
   LONG way_from_right;
   SHORT Forget_is_my_job;
   LONG JMP_is_for_assembly;
   LONG assembly_I_work_for_cops;

   BOOL allOfTheAbove;

   int Elligence_says_anyways_thinkAboutIt_**break**_if_we_code_like_this_we_d_be_monkeys;

}
// Sometimes Programming is supposed to convey the meaning and the essence of the task at hand. It is // there to serve a purpose and to keep it alive. While you are not looking, your program is doing  // its thing. Do you trust it?
// This is how you can...
// ----------
// **Break**; Please, take a **Break**;

/ *不过只是一个小问题。阅读以上内容时,您喝了多少咖啡?IT 有时会破坏系统* /


0

在某一点退出代码。这提供了更好的代码可读性。在两者之间添加return语句(多个出口)将使调试困难。


0

如果您具有“查找”类型的代码,则可以将switch-case子句本身打包在一个方法中。

我在为娱乐而开发的“爱好”系统中有一些:

private int basePerCapitaIncomeRaw(int tl) {
    switch (tl) {
        case 0:     return 7500;
        case 1:     return 7800;
        case 2:     return 8100;
        case 3:     return 8400;
        case 4:     return 9600;
        case 5:     return 13000;
        case 6:     return 19000;
        case 7:     return 25000;
        case 8:     return 31000;
        case 9:     return 43000;
        case 10:    return 67000;
        case 11:    return 97000;
        default:    return 130000;
    }
}

(是的。这是GURPS空间...)

我同意其他人的观点,在大多数情况下,您应该避免在一个方法中返回多个,并且我确实认识到,最好将其实现为数组或其他形式。我只是发现switch-case-return非常容易与输入和输出之间具有1-1关联的查找表匹配,就像上面的事情(角色扮演游戏充满了它们,我确定它们存在于其他游戏中)以及“企业”):D

另一方面,如果案例比较复杂,或者在切换语句之后发生了某些事情,我不建议在其中使用return,而是在switch中设置一个变量,以一个中断结尾并返回最后变量的值。

(在……第三手上……您始终可以将开关重构为自己的方法……我怀疑它会对性能产生影响,而且如果现代编译器甚至可以将其识别为它也不会令我感到惊讶可以内联的东西...)

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.