break
statementをfor
ループ?
たとえば、配列の値を検索しています。 forループ内で比較し、値が見つかったらbreak;
を使用してforループを終了します。
これは悪い習慣ですか?代替が使用されているのを見ました:変数vFound
を定義し、値が見つかったらtrueに設定し、vFound
ステートメント条件でfor
を確認します。しかし、この目的のためだけに新しい変数を作成する必要がありますか?
通常のCまたはC++ forループのコンテキストで尋ねています。
追伸: MISRAコーディングガイドライン は、breakの使用を推奨しません。
ここにはたくさんの答えがありますが、私はまだこれが言及されているのを見ていません:
整然とした読みやすいループを記述すると、forループでbreak
またはcontinue
を使用することに関連する「危険」のほとんどが無効になります。ループの本体が複数の画面長にまたがり、複数のネストされたサブブロックがある場合、はい、ブレーク後に一部のコードが実行されないことを簡単に忘れることができます。ただし、ループが短くて要点を示している場合、breakステートメントの目的は明らかです。
ループが大きくなりすぎている場合は、代わりにループ内で1つ以上の適切な名前の関数呼び出しを使用します。これを避ける唯一の本当の理由は、処理のボトルネックのためです。
いいえ、ブレークは正しい解決策です。
ブール変数を追加すると、コードが読みにくくなり、潜在的なエラーの原因が追加されます。
「break」ステートメントを含むあらゆる種類のプロフェッショナルコードを見つけることができます。必要なときにこれを使用することは完全に理にかなっています。あなたの場合、このオプションは、ループから抜け出すためだけに別の変数を作成するよりも優れています。
break
ループでcontinue
と同様にfor
を使用することはまったく問題ありません。
コードを簡素化し、読みやすさを向上させます。
悪い習慣からほど遠い、Python(および他の言語?)は for
ループ 構造を拡張し、その一部がonlyループが実行されない場合break
に実行されます。
for n in range(5):
for m in range(3):
if m >= n:
print('stop!')
break
print(m, end=' ')
else:
print('finished.')
出力:
stop!
0 stop!
0 1 stop!
0 1 2 finished.
0 1 2 finished.
break
およびその便利なelse
なしの同等のコード:
for n in range(5):
aborted = False
for m in range(3):
if not aborted:
if m >= n:
print('stop!')
aborted = True
else:
print(m, end=' ')
if not aborted:
print('finished.')
一般的なルール:ルールに従うために、より厄介で読みにくい操作を行う必要がある場合は、ルールを破ってからルールを破ってください。
何かを見つけるまでループする場合、外に出たときに、見つかったものと見つからなかったものを区別する問題に遭遇します。あれは:
for (int x=0;x<fooCount;++x)
{
Foo foo=getFooSomehow(x);
if (foo.bar==42)
break;
}
// So when we get here, did we find one, or did we fall out the bottom?
したがって、フラグを設定するか、「found」値をnullに初期化できます。しかし
そのため、一般に検索を関数にプッシュすることを好みます。
Foo findFoo(int wantBar)
{
for (int x=0;x<fooCount;++x)
{
Foo foo=getFooSomehow(x);
if (foo.bar==wantBar)
return foo;
}
// Not found
return null;
}
これは、コードを整理するのにも役立ちます。メイン行では、「find」は単一のステートメントになり、条件が複雑な場合は1回だけ記述されます。
Breakステートメントの使用に本質的に問題はありませんが、ネストされたループは混乱を招く可能性があります。読みやすさを改善するために、多くの言語( 少なくともJavaはあります )は、ラベルの区切りをサポートし、読みやすさを大幅に改善します。
int[] iArray = new int[]{0,1,2,3,4,5,6,7,8,9};
int[] jArray = new int[]{0,1,2,3,4,5,6,7,8,9};
// label for i loop
iLoop: for (int i = 0; i < iArray.length; i++) {
// label for j loop
jLoop: for (int j = 0; j < jArray.length; j++) {
if(iArray[i] < jArray[j]){
// break i and j loops
break iLoop;
} else if (iArray[i] > jArray[j]){
// breaks only j loop
break jLoop;
} else {
// unclear which loop is ending
// (breaks only the j loop)
break;
}
}
}
Break(およびreturn)ステートメントは、多くの場合増加します 循環的複雑度 これは、すべての場合においてコードが正しいことをしていることを証明するのを難しくします。
特定のアイテムのシーケンスを反復処理するときにブレークを使用することを検討している場合は、データを保持するために使用されるデータ構造を再検討する必要があります。セットやマップなどを使用すると、より良い結果が得られる場合があります。
breakは完全に受け入れられるステートメントです(continue、btwも同様です)。それはすべてコードの可読性に関するものです-複雑すぎるループなどがなければ、問題ありません。
gotoと同じリーグではなかった。 :)
言語に依存します。ここでブール変数をチェックすることもできますが:
for (int i = 0; i < 100 && stayInLoop; i++) { ... }
配列を繰り返し処理する場合、それを行うことはできません。
for element in bigList: ...
とにかく、break
は両方のコードを読みやすくします。
break
の使用を推奨する他の人に同意します。明らかな結果的な質問は、なぜ誰かがそうでなければお勧めするのでしょうか?さて... breakを使用すると、ブロック内の残りのコードと残りの反復をスキップします。時々これはバグを引き起こします、例えば:
ブロックの上部で取得したリソースは下部で解放される場合があります(これはfor
ループ内のブロックについても同様です)が、「早期」終了がbreak
ステートメント(「モダン」C++、「RAII」は、これを信頼性の高い例外安全な方法で処理するために使用されます。基本的に、オブジェクトデストラクターは、スコープがどのように終了しても、リソースを確実に解放します)
誰かが、for
ステートメントの条件付きテストを、他の非ローカライズされた終了条件があることに気付かずに変更する場合があります
ndimの答えは、一部の人々はbreak
sを避けて比較的一貫したループ実行時間を維持するかもしれないが、break
をブール値の早期終了制御変数の使用と比較していた
そのようなバグを観察する人々は、この「ブレークなし」のルールによって防止/緩和できることに気づきます...実際、「構造化プログラミング」と呼ばれる「安全な」プログラミングには、各関数が持つはずの全体的な関連戦略があります入り口と出口も1つだけです(つまり、gotoなし、早期復帰なし)。それはいくつかのバグを排除するかもしれませんが、間違いなく他のものを導入します。なぜ彼らはそれをするのですか?
この例では、forループの反復回数はわかりません。代わりにwhileループを使用しないのはなぜですか?
したがって、一般的にbreak statemementを使用する必要はありません。ループはwhileループとしてより適切に記述できるためです。
break
を使用することは完全に有効です。他の人が指摘しているように、goto
と同じリーグにはありません。
値が配列内で見つかったかどうかをループ外で確認する場合は、vFound
変数を使用することもできます。保守性の観点からも、終了基準を通知する共通のフラグを使用すると便利です。
その時点でSTOP処理を完了するのが悪い習慣になる理由はわかりません。
組み込みの世界では、次の構成を使用する多くのコードがあります。
while(1)
{
if (RCIF)
gx();
if (command_received == command_we_are_waiting_on)
break;
else if ((num_attempts > MAX_ATTEMPTS) || (TickGet() - BaseTick > MAX_TIMEOUT))
return ERROR;
num_attempts++;
}
if (call_some_bool_returning_function())
return TRUE;
else
return FALSE;
これは非常に一般的な例であり、多くのことがカーテンの後ろで、特に割り込みが発生しています。これを定型的なコードとして使用しないでください。私は単に例を説明しようとしています。
私の個人的な意見では、ループ内に無期限に残ることを防ぐために適切な注意を払う限り、この方法でループを書くことは何の問題もないと考えています。
現在取り組んでいるコードベース(40,000行のJavaScript)について分析を行いました。
22個のbreak
ステートメントのみが見つかりましたそれらの:
switch
ステートメント内で使用されました(合計で3つのswitchステートメントしかありません!)。for
ループ内で使用されました-すぐに別の関数にリファクタリングされると分類し、return
ステートメントに置き換えられたコード。break
内部while
ループについては... git blame
を実行して、このがらくたを書いた人を確認しました!私の統計によると:break
がswitch
の外で使用されている場合、それはコードの匂いです。
continue
ステートメントも検索しました。見つかりません。
ユースケースに依存します。 forループの実行時間を一定にする必要があるアプリケーションがあります(たとえば、いくつかのタイミング制約を満たすため、またはタイミングベースの攻撃からデータ内部を隠すため)。
これらの場合、フラグを設定し、すべてのfor
ループ反復が実際に実行された後にのみフラグ値をチェックすることも理にかなっています。もちろん、すべてのforループの反復では、ほぼ同じ時間がかかるコードを実行する必要があります。
実行時を気にしない場合... break;
およびcontinue;
を使用して、コードを読みやすくします。
MISRA 98ルールでは、C devで私の会社で使用されていますが、breakステートメントは使用されません...
編集:MISRA '04ではブレークが許可されています
同意しません!
独自のforループの組み込み機能を無視するのはなぜですか?車輪を再発明する必要はありません。
Forループの一番上にチェックを入れておくのがより理にかなっていると思います
for(int i = 0; i < myCollection.Length && myCollection[i].SomeValue != "Break Condition"; i++)
{
//loop body
}
または最初に行を処理する必要がある場合
for(int i = 0; i < myCollection.Length && (i == 0 ? true : myCollection[i-1].SomeValue != "Break Condition"); i++)
{
//loop body
}
これにより、すべてを実行し、よりクリーンなコードを作成する関数を作成できます。
for(int i = 0; i < myCollection.Length && (i == 0 ? true : myCollection[i-1].SomeValue != "Break Condition"); i++)
{
DoAllThatCrazyStuff(myCollection[i]);
}
または、条件が複雑な場合は、そのコードも外に移動できます!
for(int i = 0; i < myCollection.Length && BreakFunctionCheck(i, myCollection); i++)
{
DoAllThatCrazyStuff(myCollection[i]);
}
ブレークに満ちた「プロフェッショナルコード」は、私にはプロフェッショナルコードのようには聞こえません。怠codingなコーディングのようですね;)
もちろん、break;
はforループまたはforeachループを停止するソリューションです。 foreachおよびforループのphpで使用し、動作していることがわかりました。