使用“转到”语句不好?(Is using a 'goto' statement ba

2019-06-17 16:50发布

做一些研制后如何通过二次回路断线

while (true) { // Main Loop
   for (int I = 0; I < 15; I++) { // Secondary loop
       // Do Something
       break; // Break main loop?
   }
}

大多数人建议称之为“转到”功能
展望如下面的例子:

while (true) { // Main Loop
   for (int I = 0; I < 15; I++) { // Secondary Loop
       // Do Something
       goto ContinueOn; // Breaks the main loop
   }
}
ContinueOn:

然而; 我经常听说“转到”语句是不好的做法。 下面的图片是完全说明我的观点:

所以

  • 有多糟糕goto语句真的,为什么?
  • 有没有打破主循环比使用“转到”语句更有效的方式?

Answer 1:

编辑:

有多糟糕goto语句真的,为什么?

这要看具体情况。 我不记得任何时候,我发现它使代码重构相比更具可读性。 这也取决于可读性的个人观点 - 有些人不喜欢比别人多,因为从其他的答案清晰。 ( -有效地都在C#5异步/ AWAIT代码是基于大量的goto方法的作为关注点,它广泛用于生成的代码)。

问题是,那里的情况下goto一般用往往是那种情况下无论如何重构艾滋病的事情-而goto与越来越难以遵循代码变得更复杂的解决方案棒。

有没有打破主循环比使用“转到”语句更有效的方式?

绝对。 提取你的方法到一个单独的功能:

while (ProcessValues(...))
{
    // Body left deliberately empty
}

...

private bool ProcessValues()
{
   for (int i = 0; i < 15; i++)
   {
       // Do something
       return false;
   }
   return true;
}

我一般喜欢做这种过度引入额外的本地变量来跟踪“有我完成了” - 虽然这会努力的,当然。



Answer 2:

有多糟糕goto语句真的,为什么?

它是给所有正常的原因非常糟糕。 在不支持它们的语言模仿标记循环时,这是prefectly罚款。

与真正应该被理解为同一单位在许多情况下,分散的逻辑功能将取代它。 这使得它难以阅读。 没有人喜欢遵循的功能没有做任何事情,直到在旅途的终点,当你已经有点忘记你来自哪里开始痕迹。

与布尔和一堆额外的IFS和休息更换它是真的很笨重,使其难以按照真实意图,像任何噪音。

在java的 (和JavaScript),这是完全可以接受的(标记为循环):

outer: while( true ) {
    for( int i = 0; i < 15; ++i ) {
        break outer;
    }
}

在C#中,它看起来像很接近相当于是不是:

while( true ) {
   for (int I = 0; I < 15; I++) { 
       goto outer;
   }
}
outer:;

因为这个词的goto ,这使得人们放弃他们所有的常识,使他们的上下文链接XKCD不管一种心理作用。

有没有打破主循环比使用“转到”语句更有效的方式?

在某些情况下没有,这就是为什么其他语言提供标记环和C#提供了goto 。 请注意,您的例子过于简单,这使得因为他们量身定做的示例中的变通看起来还不错。 其实,我也可以同样建议如下:

   for (int I = 0; I < 15; I++) {
       break;
   }

这个怎么样:

int len = 256;
int val = 65536;

for (int i = 0; i < len; i++)
{
    for (int j = 0; j < len; j++)
    {
        if (i + j >= 2 * val)
        {
            goto outer;
        }
        val = val / 2;
    }
}
outer:;

这是否仍然看起来好给你:

int len = 256;
int val = 65536;

for (int i = 0; i < len; i++)
{
    if (!Inner(i, ref val, len))
    {
        break;
    }
}

private bool Inner(int i, ref int val, int len)
{
    for (int j = 0; j < len; j++)
    {
        if (i + j >= 2 * val)
        {
            return false;
        }

        val = val / 2;
    }

    return true;
}


Answer 3:

我将与所有在这里的其他答案的强烈反对。 你目前使用的代码goto有什么不妥的地方。 还有一个原因是C#有一个goto语句,恰恰是这些类型的场景,你形容。

goto压根儿就因为在20世纪70年代及以前人们一负的耻辱,其中控制流程跃升遍布因为地方会写可怕的,完全不可维护的代码goto 。 C#的goto甚至不允许方法之间的转换! 然而,仍然有反对这种不合理的歧视。

在我看来,是绝对没有错用“现代” goto跳出内部循环。 该“方案”的人提供最终总是被更加复杂和难以阅读

方法一般都应该是可重复使用的 。 使整个单独的方法为一个循环,这将永远只能得到从一个位置叫的内部,并且其中方法实现最终可能是在源代码中的一些较远的地方,是不是在改善。

这种愚蠢的运动,以避免goto基本上是政治正确的,但在编程世界的等价物。



Answer 4:

我同意有关如何坏转到大部分答案。

我sugestion避免GOTO是做这样的事情:

while (condition) { // Main Loop
   for (int i = 0; i < 15; i++) { // Secondary loop
       // Do Something
       if(someOtherCondition){
              condition = false // stops the main loop
              break; // breaks inner loop
       }
   }
}


Answer 5:

我有时用“GOTO”,我发现它看起来不错,像上面的例子;

bool AskRetry(Exception ex)
{
  return MessageBox.Show(you know here...) == DialogResult.Retry;
}

void SomeFuncOrEventInGui()
{
  re:try{ SomeThing(); }
  catch (Exception ex)
  {
    if (AskRetry(ex)) goto re;
    else Mange(ex); // or throw or log.., whatever...
  }
}

我知道你可以做同样的事情递归,但谁在乎它只是工作,我使用。



Answer 6:

我的一位同事(谁在固件程序拥有15年以上),我使用goto所有的时间。 然而,我们只用它来处理异常! 例如:

if (setsockopt(sd,...)<0){
goto setsockopt_failed;
}
...

setsockopt_failed:
close(sd);

据我所知,这是C.处理异常的最好方式,我相信,我支持C#了。 另外,我不是唯一一个谁是这样认为的: 在C或C好goto方法的例子++



Answer 7:

我个人喜欢把goto语句为“goto语句导致地狱” ......在许多方面,这是真实的,因为它可以导致高度不可维护的代码和非常糟糕的做法。

话虽这么说,它仍然是实现的一个原因,而使用时,应该尽量少用,如果没有其他解决方案可用。 面向对象的语言借给自己并不是真正需要它(很多)。

唯一的时候,我曾经看到它使用了这些天是混淆...使用goto语句创建一个从地狱代码,所以人们将试图理解它而却步的GOOT例子!

有些语言取决于相当于关键字。 例如,在x86的装配台你的关键字,如JMP(跳转),JE(跳转如果相等)和JZ(跳转如果为零)。 这些经常需要使用汇编语言,因为在这个级别没有OO,还有一些其他的方法在应用程序中走动。

据我所知......呆在远离它,除非绝对必要的。



文章来源: Is using a 'goto' statement bad?