61

二次ループを突破する方法についていくつかの調査を行った後

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

ほとんどの人は、「goto」関数を呼び出すことをお勧めします
。次の例のように見えます。

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

でも; 「goto」ステートメントは悪い習慣だとよく耳にします。以下の図は、私のポイントを完全に示しています。 シリーズが見つかりました

そう

  • goto ステートメントは実際にはどれほど悪いのでしょうか? またその理由は?
  • 「goto」ステートメントを使用するよりもメインループを中断する効果的な方法はありますか?
4

7 に答える 7

55

編集:

goto ステートメントは実際にはどれほど悪いのでしょうか? またその理由は?

それは正確な状況によって異なります。リファクタリングよりもコードが読みやすくなったのはいつか思い出せません。また、読みやすさに対する個人的な見方にも依存します。他の回答から明らかなように、他の人よりも嫌いな人もいます。(興味深い点として、これは生成されたコードで広く使用されています。C# 5 のすべての async/await コードは、事実上多くの goto に基づいています)。

問題は、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;
}

私は通常、追加のローカル変数を導入して「完了したか」を追跡するよりも、これを行うことを好みますが、もちろんそれも機能します。

于 2012-08-10T16:56:04.643 に答える
50

ここでの他のすべての回答には強く反対します。あなたが使用して提示するコードにgotoは何の問題もありません。C#にステートメントがあるのには理由がありgoto、それはまさにあなたが説明するこれらのタイプのシナリオのためです。

goto1970 年代以前の人々は、goto. C# ではgoto、メソッド間の遷移さえ許可されていません! それでも、それに対するこの不合理な汚名はまだあります。

私の意見では、「モダン」を使用してgoto内側のループから抜け出すことにはまったく問題はありません。人々が提供する「代替手段」は常に、より複雑で読みにくくなります

メソッドは通常、再利用可能であると想定されています。ループの内側の部分に完全に別のメソッドを作成し、その 1 つの場所からのみ呼び出され、メソッドの実装がソース コード内の離れた場所に配置される可能性がある場合、改善にはなりません。

于 2012-08-10T18:10:44.483 に答える
43

goto ステートメントは実際にはどれほど悪いのでしょうか? またその理由は?

与えられたすべての通常の理由から、それは本当に悪いです。サポートされていない言語でラベル付きループをエミュレートする場合は、まったく問題ありません。

これを関数に置き換えると、多くの場合、実際には同じ単位として読み取られるべきロジックが散らばってしまいます。これにより、読みにくくなります。どこから出発したかをいくらか忘れてしまう旅の終わりまで、実際には何もしない機能の跡をたどりたいと思う人はいません。

それをブール値と追加の if と break で置き換えるのは本当に扱いにくく、ノイズのように本当の意図に従うのが難しくなります。

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をリンクさせるという心理的効果があります。

「goto」ステートメントを使用するよりもメインループを中断する効果的な方法はありますか?

ない場合もあります。そのため、他の言語ではラベル付きループが提供され、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;
}
于 2012-08-11T10:00:40.267 に答える
11

私は時々 "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...
  }
}

同じことを再帰的に行うことができることは知っていますが、誰がそれを気にするだけで機能し、私は使用します。

于 2014-12-01T10:08:03.480 に答える
-2

個人的に私はgotoを「gotoは地獄につながる」と考えるのが好きです...そして多くの点でこれは非常に保守不可能なコードと本当に悪い習慣につながる可能性があるので真実です。

そうは言っても、それはまだ理由のために実装されており、他の解決策が利用できない場合は、使用するときは控えめに使用する必要があります。オブジェクト指向言語は、実際にはそれを必要としない(多くの場合)のに役立ちます。

最近使用されているのを私が目にするのは、難読化されていることだけです... gotoを使用して地獄からコードを作成するという素晴らしい例なので、人々はそれを理解しようとするのを思いとどまるでしょう!

一部の言語は、同等のキーワードに依存しています。たとえば、x86アセンブリには、JMP(Jump)、JE(Jump if Equal)、JZ(Jump if Zero)などのキーワードがあります。このレベルにはOOがなく、アプリケーション内を移動する方法は他にほとんどないため、これらはアセンブリ言語で頻繁に必要になります。

AFAIK ...絶対に必要でない限り、それから離れてください。

于 2012-08-10T22:32:56.950 に答える