web-dev-qa-db-ja.com

if-elseの代わりにreturn / continueステートメントを使用する必要がありますか?

C、C++、およびC#では、関数またはループステートメント内で条件を使用する場合、continueまたはreturnステートメントをできるだけ早く使用して、-を取り除くことができます。 elseif-elseステートメントのブランチ。例えば:

while( loopCondition ) {
    if( innerCondition ) {
        //do some stuff
    } else {
        //do other stuff
    }
}

になります

 while( loopCondition ) {
    if( innerCondition ) {
        //do some stuff
        continue;
    }
    //do other stuff
}

そして

void function() {
    if( condition ) {
        //do some stuff
    } else {
        //do other stuff
    }
}

になります

void function() {
    if( condition ) {
        //do some stuff
        return;
    }
    //do other stuff
}

「after」バリアントは、if-elseブランチが長い場合、この変更によりelseブランチのインデントがなくなるため、読みやすくなる可能性があります。

そのような返品/継続の使用は良い考えですか?メンテナンスや読みやすさの問題はありますか?

28
sharptooth

コンパイラはほぼ確実に同じコードを生成します。そうでない場合でも、違いはおそらく無関係です。したがって、関連する議論は確かに人々がそれをどのように読むかです。

したがって、問題は「//何かをする」と「他のことをする」がどれほど似ているかということです。概念的に類似している場合は、if/elseを使用します。概念的に異なる場合は、continue/returnを使用してください。

13
MSalters

いずれかを選択する私の個人的なアプローチは、if部分の本体が非常に短い場合(最大3行または4行)、return/continueバリアントを使用するのが理にかなっているというものです。本体が長いと、制御フローを追跡するのが難しくなるため、elseバージョンを選択します。

その結果、通常、このアプローチでは、return/continueスタイルの使用が次のいずれかの方法を使用してこれを処理するではなく一部のデータをスキップしてそれ以上の処理を回避するに制限されます。 (これはif/elseに適しています)。

31
Mehrdad Afshari

それは枝の長さに少し依存します。最初のifチェックが短く、本文が長い場合は、説明するreturn/continueの使用が適切です。 ifelseの両方の部分が長い場合は、それらを抽出して別々の関数にします。

私はCodeCompleteを読むことをお勧めします、それはこのようなことをたくさん議論します。

12
Johan Kotlinski

終了基準を最初に処理すると、コードが読みやすくなります。私はいつも、長いコード実行を必要とする条件よりも、ブレークまたはリターンを必要とする条件をチェックすることを好みます。私が好む:

 if (termination condn) 
      return;
 // code 
 // code

if (success condn)
{
  // code
  // code
}
else
 return;

これにより、コードの読み取りと理解が容易になります。

11
Rashmi Pandit

Glibの答えは、それはすべて依存するということです。

私の一般的な感覚は、conditionがまれな、ガード(nullのチェックなど)またはエラー状態である場合、returnまたはcontinueを使用する傾向があるということです。

それが予想されるケースである場合、私はあなたの最初のアプローチを使用する傾向があります。

ただし、「傾向がある」と言ったことに注意してください。これらと条件の境界はあいまいであり、プロジェクトや私が誰と協力しているかによって変更される可能性があります。

6
ChrisF

私は通常好きです

while( loopCondition ) {
    if( innerCondition ) {
        DoStuff();
    } else {
        DoOtherStuff(); 
    }
}

doStuffの長さが1〜2行のしきい値を超えた場合、続行するのは難しい場合があります(そして、意図を見逃しがちです)。これは、ロジックをいくつかの小さなメソッドにリファクタリングする良い機会のようです。

4
Sam Saffron

時期尚早の最適化のために読みやすさを犠牲にしないでください。

例えば:

void function() {
    if( condition ) {
        //do some stuff
    } else {
        //do other stuff
    }
}

ほとんどの場合、バイナリは同等です

void function() {
    if( condition ) {
        //do some stuff
        return;
    }
    //do other stuff
}

(つまり、結果のコードはおそらく同じです)。ただし、コードがXまたはYのいずれかになることがはっきりとわかるため、前者の可読性ははるかに優れています。

4
elmuerte

1)入力またはオブジェクトの状態の検証。次のコード:

void function() {
    if( condition ) {
        //do some stuff
        return;
    }
    //do other stuff
}

条件が機能が機能するための何らかの要件である場合に適しています。これは、入力検証またはオブジェクト状態検証の段階です。その場合、すぐにreturnを使用して強調するのが正しいと感じます。その関数は、まったく実行されませんでした。

2)多段処理。ループがコレクションから要素をポップし、それらを多段階で処理する場合、while/continueは適切です。

while(foo = bar.getNext()) {
   if(foo.empty())
       continue;
   if(foo.alreadyProcessed())
       continue;
   // Can we take a shortcut?
   if(foo.tryProcessThingsYourself())
       continue;
   int baz = foo.getBaz();
   if(baz < 0) {
       int qux = foo.getQux();
       if(qux < 0) {
         // Error - go to next element
         continue;
       }
   }
   // Finally -- do the actual processing
   baz = baz * 2;
   foo.setBaz(baz);
}

この例は、一連の多段階処理が実行され、各処理がさまざまな場所でさまざまな条件によって中断される可能性があるシナリオで、続行を使用するのがいかに自然であるかを示しています。

注意:plinth投稿された実際の例。2)の内容に従います。

3)原則。何かが中断されたという事実に対応する場合は、continueおよびreturnを使用します。 elseが実際の処理の一部である場合、私はelseを使用します。

3
anon

考えられるメンテナンスの問題の1つは、関数に複数のリターンがある場合、デバッグ時にブレークポイントを固定したり、リターンでトレースしたりするのが難しいことです。これが問題になることはめったにありませんが、リターンポイントを逃すと苦痛になります。ループ条件とループの先頭はどちらもまだ一意であるため、ループを継続することはそれほど重要ではないと思います。

それとは別に:他のみんなが言うこと。 「いくつかのもの」と「他のもの」の相対的な長さ、重要性、可能性に応じて、最も読みやすいことを行います。ケースが短く、些細で、ありそうもないケースであるほど、特別なケースの制御フローを持つことはそれほど邪魔になりません。

2
Steve Jessop

にやにや笑いについては、会社のコードベース全体で「続行」を検索しました。それがどこで使用されているかを知るためだけに。 1つのソリューションで59のプロジェクト全体で695回、約1500のソースファイルを使用します。

それらが使用されているのを私が見る主な方法は、クイックフィルターとしてです。

foreach (Frobozz bar in foo) {
    if (QuickFilterExclude(bar))
        continue;
    // extensive processing
}

予想される例外からの回復:

foreach (Frobozz bar in foo) {
    Baz result = new Baz(kDefaultConfiguration);
    try {
        Baz remoteResult = boo.GetConfiguration();
    }
    catch (RemoteConnectionException) {
        continue;
    }
    result.Merge(remoteResult);
    ReportResult(result);
}

そして最後に州の機械で。

2
plinth

他の人が言ったように、物事が短い場合にのみリターン/コンティニューを使用してください。

個人的には、次のように1行で書き込むことができる場合にのみcontinueを使用します。

while( loopCondition ) {
    if( innerCondition ) continue;

    //do other stuff
}

コードが醜くならずにこのように書くことができない場合は、if/else。

2
Joakim Elofsson

メソッドまたはループからジャンプするときは、何もする必要がないため、通常はif-returnメソッドを使用します。

かなりの作業が行われているために体が長くなる場合は、if-elseを使用し、おそらく#regionを使用してブロックにわかりやすい名前を付け、制御フローを研究するために簡単に折りたたむことができるようにすることをお勧めします。それまたは別のメソッドを作成します:)

1
Thorarin

私のコードには次のものがありました:

    while(){
      boolean intersect = doesIntersect(interval_1,interval_2);
      if(!intersect){
         array.add(interval_2);
         if(// another condition){
            // Do some thing here
         }
         continue;
      }
      // other stuff to do if intersect
    }

continueを使用するか、elseを使用するか混乱していましたが、内部のif条件によってelseが読みにくくなる可能性があると判断したため、continueを使用しました。

読みやすさが重要だと思います!

0
Abdelrahman Aly