Manchmal brauche ich für Schleifen, die eine Pause wie folgt brauchen:
for(int i=0;i<array.length;i++){
//some other code
if(condition){
break;
}
}
Ich fühle mich beim Schreiben unwohl
if(condition){
break;
}
weil es 3 Codezeilen verbraucht. Und ich fand die Schleife kann umgeschrieben werden als:
↓
for(int i=0;i<array.length && !condition;i++){
//some other code
}
Meine Frage ist also, ob es eine gute Praxis ist, die Bedingung in das Bedingungsfeld zu verschieben, um Codezeilen nach Möglichkeit zu reduzieren.
coding-style
loops
ocomfd
quelle
quelle
condition
im Besonderen ist.for(int i=0;i<array.length && !condition;i++)
Ist relativ ungewöhnlich und wird möglicherweise von jemandem übersehen, der nur den Code überfliegt. Dies ist möglicherweise ein guter Anwendungsfall für einewhile
oderdo while
Schleife, die in der Schleifendefinition häufig mehrere Unterbrechungsbedingungen enthält.Antworten:
Diese beiden Beispiele, die Sie angegeben haben, sind funktional nicht gleichwertig. Im Original wird der Bedingungstest nach dem Abschnitt "Ein anderer Code" durchgeführt, während er in der modifizierten Version zuerst am Anfang des Schleifenkörpers durchgeführt wird.
Der Code sollte niemals mit dem einzigen Zweck umgeschrieben werden, die Anzahl der Zeilen zu verringern. Natürlich ist es ein schöner Bonus, wenn es so funktioniert, aber es sollte niemals auf Kosten der Lesbarkeit oder Korrektheit geschehen.
quelle
Ich kaufe nicht das Argument, dass "es 3 Zeilen Code verbraucht" und daher schlecht ist. Immerhin könnte man es einfach so schreiben:
und nur eine Zeile verbrauchen.
Wenn das
if
auf halbem Weg durch die Schleife erscheint, muss es natürlich als separater Test existieren. Wenn dieser Test jedoch am Ende des Blocks angezeigt wird, haben Sie eine Schleife erstellt, die an beiden Enden der Schleife einen Dauertest enthält, der möglicherweise die Komplexität des Codes erhöht. Beachten Sie jedoch, dass derif (condition)
Test manchmal erst Sinn macht, nachdem der Block ausgeführt wurde.Wenn dies jedoch nicht der Fall ist, verwenden Sie den anderen Ansatz:
Die Exit-Bedingungen werden zusammengehalten, was die Dinge vereinfachen kann (insbesondere wenn " ein anderer Code " lang ist).
Hier gibt es natürlich keine richtige Antwort. Achten Sie also auf die Redewendungen der Sprache, die Kodierungskonventionen Ihres Teams usw. Alles in allem würde ich jedoch den Single-Test-Ansatz wählen, wenn dies funktional sinnvoll ist.
quelle
Diese Art von Frage hat schon fast so lange Diskussionen ausgelöst wie die Programmierung. Um meinen Hut in den Ring zu werfen, würde ich mich für die Version mit der
break
Bedingung entscheiden und hier ist der Grund (für diesen speziellen Fall):Die
for
Schleife ist nur dazu da, die Iterationswerte in der Schleife anzugeben. Das Kodieren des Unterbrechungszustands innerhalb dessen trübt nur die logische IMO.Durch
break
die Angabe eines separaten Elements wird deutlich, dass die Werte während der normalen Verarbeitung den in derfor
Schleife angegebenen Werten entsprechen und die Verarbeitung fortgesetzt werden sollte, sofern die Bedingung nicht vorliegt.Als Hintergrund habe ich mit dem Codieren von a begonnen
break
, dann die Bedingungfor
jahrelang in die Schleife gestellt (unter der Leitung eines außergewöhnlichen Programmierers) und dann zumbreak
Stil zurückgekehrt, weil er sich einfach viel sauberer anfühlte (und der vorherrschende Stil in war) die verschiedenen Codebücher, die ich konsumiert habe).Es ist ein weiterer dieser heiligen Kriege am Ende des Tages - manche sagen, man sollte niemals künstlich aus einer Schleife ausbrechen, sonst ist es keine echte Schleife. Tun Sie, was Sie für lesbar halten (sowohl für sich selbst als auch für andere). Wenn Sie die Tastenanschläge wirklich reduzieren möchten, spielen Sie am Wochenende Code-Golf - Bier optional.
quelle
for
Schleifen verwendet werden, wenn die Anzahl der Iterationen bekannt ist (z. B. wenn es keine Unterbrechungsbedingung gibt, aber das Ende des Arrays / der Liste) undwhile
wenn dies nicht der Fall ist . Dies scheint für einewhile
Schleife der Fall zu sein . Wenn es um Lesbarkeit geht, ist dasidx+=1
Lesen in der Schleife viel sauberer als in einemif/else
Blockfor(int i=0; i<something;i++)
Loops gewöhnt, dass die Hälfte der Entwickler sich nicht wirklich daran erinnert, dassfor
Loops unterschiedlich verwendet werden können und es daher schwierig ist, den&&condition
Teil zu verstehen .for(;;)
...for
Schleifen sind für die Iteration über etwas 1 - sie sind nicht nur lol-let-pull-some-random-stuff-from-the-body-und-put-them-in-the-loop-Header - die drei Ausdrücke haben sehr spezifische Bedeutungen:Die Idee ist, die Iterationsbehandlung ( wie iteriert wird) von der Logik innerhalb der Schleife zu trennen ( was in jeder Iteration zu tun ist). In vielen Sprachen gibt es normalerweise eine For-Each-Schleife, die Sie von den Einzelheiten der Iteration befreit. Selbst wenn Ihre Sprache dieses Konstrukt nicht besitzt oder in Ihrem Szenario nicht verwendet werden kann, sollten Sie den Schleifenkopf trotzdem einschränken zur Iterationsbehandlung.
Sie müssen sich also fragen: Besteht Ihre Bedingung in Bezug auf die Iterationsbehandlung oder in Bezug auf die Logik in der Schleife? Wahrscheinlich handelt es sich um die Logik innerhalb der Schleife. Sie sollte daher innerhalb der Schleife und nicht im Header überprüft werden.
1 Im Gegensatz zu anderen Schleifen, die darauf warten, dass etwas passiert. Eine
for
/foreach
loop sollte das Konzept einer "Liste" von Elementen haben, auf denen iteriert werden soll - auch wenn diese Liste faul oder unendlich oder abstrakt ist.quelle
someFunction(array[i])
. Jetzt geht es in beiden Teilen der Bedingung um das, worüber Sie iterieren, und es wäre sinnvoll, sie&&
im Schleifenkopf zu kombinieren .for
Schleifen im Herzen sind Zähler, keine Schleifen über eine Liste, und dies wird durch die Syntaxfor
früherer Sprachen (diese Sprachen hatten oft einefor i = 1 to 10 step 2
Syntax und denstep
Befehl) unterstützt - selbst wenn ein Anfangswert zulässig ist, der nicht der Index des ersten ist Element - Hinweise auf einen numerischen Kontext, keinen Listenkontext). Der einzige Anwendungsfall, von dem ich denke, dass erfor
Schleifen unterstützt , da er nur über eine Liste iteriert, ist die Parallelisierung. Dies erfordert jetzt ohnehin eine explizite Syntax, um den Code nicht zu beschädigen, der beispielsweise eine Sortierung vornimmt.Ich empfehle die Version mit
if (condition)
. Es ist lesbarer und einfacher zu debuggen. Das Schreiben von 3 zusätzlichen Codezeilen bricht Ihnen nicht die Finger, erleichtert es jedoch der nächsten Person, Ihren Code zu verstehen.quelle
naming things
in Ordnung , aber ich vermisse so etwas wie richtig, um zu verstehen, was los ist und wann die Bruchbedingung erfüllt ist.Wenn Sie eine Sammlung durchlaufen, in der bestimmte Elemente übersprungen werden sollen, empfehle ich eine neue Option:
Sowohl Java als auch C # machen dies relativ trivial. Es würde mich nicht wundern, wenn C ++ eine Möglichkeit hätte, einen ausgefallenen Iterator zu erstellen, um bestimmte Elemente zu überspringen, die nicht zutreffen. Dies ist jedoch nur dann wirklich eine Option, wenn Ihre bevorzugte Sprache dies unterstützt. Der Grund für die Verwendung
break
liegt darin, dass Bedingungen dafür bestehen, ob Sie ein Element verarbeiten oder nicht.Ansonsten gibt es einen sehr guten Grund, Ihre Bedingung in die for-Schleife aufzunehmen - vorausgesetzt, ihre anfängliche Auswertung ist korrekt.
Ich habe an Code gearbeitet, in dem Ihre for-Schleife einige hundert Zeilen mit mehreren Bedingungen und etwas komplexer Mathematik enthält. Die Probleme, auf die Sie dabei stoßen, sind:
break
Befehle in der Logik sind schwer zu finden und manchmal überraschendIn dieser Situation empfehle ich die folgenden Richtlinien in der Reihenfolge ihrer Präferenz:
break
nach Möglichkeit zu beseitigenbreak
möglichst oben in der Schleife liegenDiese Richtlinien unterliegen immer der Richtigkeit Ihres Codes. Wählen Sie die Option, die die Absicht am besten darstellt und die Klarheit Ihres Codes verbessert.
quelle
continue
Anweisungen eliminieren kann , aber ich sehe nicht, wie viel sie helfenbreak
.takeWhile
Filter kannbreak
Anweisungen ersetzen . Wenn Sie eine haben - Java zum Beispiel bekommt sie nur bei Jave 9 (nicht, dass es so schwer ist, sie selbst zu implementieren)Ich empfehle dringend, den Ansatz der geringsten Überraschung zu wählen, es sei denn, Sie erzielen einen erheblichen Vorteil, wenn Sie etwas anderes tun.
Die Leute lesen nicht jeden Buchstaben, wenn sie ein Wort lesen, und sie lesen nicht jedes Wort, wenn sie ein Buch lesen. Wenn sie geschickt darin sind, lesen sie die Umrisse von Wörtern und Sätzen und lassen ihr Gehirn den Rest ausfüllen .
Es ist also wahrscheinlich, dass der gelegentliche Entwickler davon ausgeht, dass dies nur ein Standard für eine Schleife ist, und es sich nicht einmal ansieht:
Wenn Sie diesen Stil trotzdem verwenden möchten, empfehle ich, die Parts zu ändern
for(int i=0;i<
und;i++)
dem Gehirn des Lesers mitzuteilen, dass dies ein Standard für Loop ist.Ein weiterer Grund für
if
-break
ist, dass Sie Ihren Ansatz nicht immer mit derfor
Bedingung verwenden können. Sie müssen verwendenif
-break
wenn die Abbruchbedingung innerhalb eines zu verstecken ist zu komplexfor
Anweisung oder stützt sich auf Variablen , die nur zugänglich innerhalb der sindfor
Schleife.Wenn Sie sich also für
if
- entscheidenbreak
, sind Sie abgesichert. Wenn Sie sich jedoch fürfor
-conditions entscheiden, müssen Sie eine Mischung ausif
-break
undfor
-conditions verwenden. Um konsequent zu bleiben, werden Sie die Bedingungen hin und her bewegen müssen , um zwischen denfor
-Bedingungen und dieif
-break
immer dann , wenn sich die Bedingungen ändern.quelle
Bei Ihrer Transformation wird davon ausgegangen, dass das, was auch
condition
immer ausgewertet wird,true
wenn Sie in die Schleife eintreten. Wir können die Richtigkeit in diesem Fall nicht beurteilen, da sie nicht definiert ist.Nachdem es Ihnen hier gelungen ist, "Codezeilen zu reduzieren", schauen Sie sich das an
und wende die gleiche Transformation an, um zu gelangen
Was eine ungültige Transformation ist, da Sie jetzt bedingungslos dort vorgehen,
further code
wo Sie es zuvor nicht getan haben.Ein viel sichereres Transformationsschema besteht darin , eine separate Funktion zu extrahieren
some other code
und auszuwertencondition
quelle
TL; DR Tun Sie, was in Ihrem speziellen Fall am besten zu lesen ist
Nehmen wir folgendes Beispiel:
In diesem Fall soll keiner der Codes in der for-Schleife ausgeführt werden, wenn dies
something
zutrifft.something
Daher ist es sinnvoll, den Test von in das Bedingungsfeld zu verschieben.Dann wieder, je nachdem , ob
something
kann eingestellt werden ,true
bevor die Schleife, aber nicht in ihn, könnte dies könnte mehr Klarheit bieten:Stellen Sie sich nun Folgendes vor:
Wir senden dort eine sehr klare Botschaft. Wenn
something
dies während der Verarbeitung des Arrays wahr wird, brechen Sie an dieser Stelle den gesamten Vorgang ab. Um den Scheck in das Bedingungsfeld zu verschieben, müssen Sie Folgendes tun:Vermutlich ist die "Nachricht" verschwommen, und wir überprüfen den Fehlerzustand an zwei Stellen - was ist, wenn sich der Fehlerzustand ändert und wir einen dieser Stellen vergessen?
Es gibt natürlich viel mehr verschiedene Formen, die eine for-Schleife und Bedingung sein könnten, alle mit ihren eigenen Nuancen.
Schreiben Sie den Code so, dass er gut lesbar (dies ist offensichtlich etwas subjektiv) und kurz ist. Außerhalb eines drakonischen Satzes von Kodierungsrichtlinien haben alle "Regeln" Ausnahmen. Schreiben Sie, was Ihrer Meinung nach die beste Entscheidung ausdrückt, und minimieren Sie das Risiko zukünftiger Fehler.
quelle
Während es ansprechend sein kann, weil Sie alle Bedingungen im Schleifenkopf sehen und
break
in großen Blöcken verwirrend sein können, ist einefor
Schleife ein Muster, bei dem die meisten Programmierer eine Schleife über einen bestimmten Bereich erwarten.Insbesondere in diesem Fall kann das Hinzufügen einer zusätzlichen Unterbrechungsbedingung zu Verwirrung führen und es ist schwerer zu erkennen, ob sie funktional gleichwertig ist.
Oft ist es eine gute Alternative, eine
while
oderdo {} while
-Schleife zu verwenden, die beide Bedingungen überprüft, vorausgesetzt, Ihr Array enthält mindestens ein Element.Wenn Sie eine Schleife verwenden, die nur eine Bedingung überprüft und keinen Code aus dem Schleifenkopf ausführt, wird sehr deutlich, wann die Bedingung überprüft wird und wie der aktuelle Zustand und welcher Code mit Nebenwirkungen ist.
quelle
for(...; i <= n; ...)
macht es das Lesen des Codes tatsächlich schwieriger , wenn ich etwas anderes als ein einfaches gebundenes Überprüfen in der for-loop ( ) habe Anhalten und darüber nachdenken, was hier vor sich geht, und die Bedingung beim ersten Durchgang möglicherweise ganz verfehlen, weil ich nicht erwarte, dass sie da ist. Für mich bedeutet einefor
Schleife, dass Sie einen Bereich durchlaufen. Wenn eine spezielle Exit-Bedingung vorliegt, sollte dies mit einem explizit angegeben werdenif
, oder Sie können ein verwendenwhile
.Das ist schlecht, da Code für Menschen gedacht ist - nicht idiomatische
for
Schleifen sind oft verwirrend, was bedeutet, dass sich die Fehler eher hier verstecken, aber der ursprüngliche Code konnte möglicherweise verbessert werden, während beide beibehalten wurden kurz und lesbar.Wenn Sie einen Wert in einem Array suchen möchten (das bereitgestellte Codebeispiel ist etwas allgemein, aber es kann auch dieses Muster sein), können Sie einfach explizit versuchen, eine Funktion zu verwenden, die von einer Programmiersprache speziell für diesen Zweck bereitgestellt wird. Zum Beispiel (Pseudocode, da keine Programmiersprache angegeben wurde, variieren die Lösungen in Abhängigkeit von einer bestimmten Sprache).
Dies sollte die Lösung spürbar verkürzen und gleichzeitig vereinfachen, da Ihr Code genau sagt, was Sie benötigen.
quelle
Einige Gründe, die meiner Meinung nach besagen, sollten Sie nicht.
do...while
Schleife (nichtwhile
) erfolgen, da die Bedingung nach einer gewissen Codeausführung überprüft wird.Aber obendrein bedenken Sie Folgendes:
Können Sie es wirklich erreichen, indem Sie diese Bedingungen zu dieser
for
Bedingung hinzufügen ?quelle
Ich denke, das
break
kann eine gute Idee sein, aber keine Codezeilen zu sparen.Der Vorteil des Schreibens ohne
break
ist, dass die Nachbedingung der Schleife offensichtlich und explizit ist. Wenn Sie die Schleife beenden und die nächste Zeile des Programms ausführen, muss Ihre Schleifenbedingungi < array.length && !condition
falsch gewesen sein. Daher war entwederi
größer oder gleich Ihrer Array-Länge odercondition
ist wahr.In der Version mit
break
gibt es einen versteckten gotcha. Die Schleifenbedingung besagt, dass die Schleife beendet wird, wenn Sie für jeden gültigen Array-Index einen anderen Code ausgeführt haben. Tatsächlich gibt es jedoch einebreak
Anweisung, die die Schleife vorher beenden könnte, und Sie werden sie erst sehen, wenn Sie den Schleifencode überprüfen sehr vorsichtig. Automatische statische Analysatoren, einschließlich der Optimierung von Compilern, könnten ebenfalls Probleme haben, die Nachbedingungen der Schleife zu ermitteln.Dies war der ursprüngliche Grund, warum Edgar Dijkstra „Goto Considered Harmful“ schrieb. Es war keine Frage des Stils: Das Herausbrechen einer Schleife erschwert es, formell über den Status des Programms nachzudenken. Ich habe viele
break;
Aussagen in meinem Leben geschrieben, und als Erwachsener schrieb ich sogar einegoto
(um aus mehreren Ebenen einer leistungskritischen inneren Schleife auszubrechen und dann mit einem anderen Zweig des Suchbaums fortzufahren). Es ist jedoch weitaus wahrscheinlicher, dass ich eine bedingtereturn
Anweisung aus einer Schleife heraus schreibe (die den Code nie nach der Schleife ausführt und daher die Post-Bedingungen nicht durcheinander bringen kann) als abreak
.Nachsatz
Das Umgestalten des Codes, um dasselbe Verhalten zu erzielen, erfordert möglicherweise tatsächlich mehr Codezeilen. Ihr Refactoring kann für einen bestimmten anderen Code gültig sein oder wenn wir nachweisen können, dass dies
condition
falsch beginnt. Aber Ihr Beispiel ist im allgemeinen Fall gleichbedeutend mit:Wenn ein anderer Code kein Einzeiler ist, können Sie ihn in eine Funktion verschieben, um sich nicht zu wiederholen, und dann haben Sie Ihre Schleife beinahe zu einer rekursiven Endfunktion umgestaltet.
Ich erkenne jedoch, dass dies nicht der Hauptpunkt Ihrer Frage war, und Sie haben es einfach gehalten.
quelle
break
Anweisung gibt, wissen Sie, was die Schleifenbedingung ist und dass die Schleife stoppt, wenn diese Bedingung falsch ist. Wenn es eine gibtbreak
? Dann gibt es mehrere Möglichkeiten, wie die Schleife enden könnte, und im Allgemeinen löst das Herausfinden, wann eine von ihnen die Schleife anhalten könnte, buchstäblich das Halteproblem. In der Praxis besteht meine größere Sorge darin, dass die Schleife wie eine Sache aussieht , aber wer auch immer den Code geschrieben hat, nachdem die Schleife einen Randfall übersehen hat, der in seiner komplexen Logik verborgen ist. Sachen im Loop-Zustand sind kaum zu übersehen.Ja, aber Ihre Syntax ist unkonventionell und daher schlecht (tm)
Hoffentlich unterstützt Ihre Sprache so etwas wie
quelle
while
betont das Monster im Code - die Ausnahme, die sonst im Routine- / Alltagscode verborgen ist. Die Geschäftslogik steht im Vordergrund und im Zentrum, die Schleifenmechanik wird subsumiert. Es vermeidet die Reaktion "Warte eine Minute ..." auf diefor
Schleifenalternative. Diese Antwort behebt das Problem. absolut stimmberechtigt.Wenn Sie befürchten
for
, dass eine übermäßig komplexe Aussage schwer lesbar ist, ist dies definitiv ein berechtigtes Anliegen. Die Verschwendung von vertikalem Raum ist ebenfalls ein Thema (wenn auch weniger kritisch).(Persönlich mag ich die Regel nicht, dass
if
Anweisungen immer geschweifte Klammern haben müssen, was größtenteils die Ursache für den verschwendeten vertikalen Raum ist. Beachten Sie, dass das Problem darin besteht, vertikalen Raum zu verschwenden . Die Verwendung von vertikalem Raum mit aussagekräftigen Linien sollte kein Problem sein.)Eine Möglichkeit besteht darin, es in mehrere Zeilen aufzuteilen. Dies sollten Sie auf jeden Fall tun, wenn Sie sehr komplexe
for
Anweisungen mit mehreren Variablen und Bedingungen verwenden. (Dies ist für mich eine bessere Nutzung des vertikalen Raums, um so vielen Zeilen wie möglich etwas Sinnvolles zu geben.)Ein besserer Ansatz könnte darin bestehen, zu versuchen, eine deklarativere und weniger imperativere Form zu verwenden. Dies hängt von der Sprache ab, oder Sie müssen möglicherweise Ihre eigenen Funktionen schreiben, um diese Funktion zu aktivieren. Es kommt auch darauf an, was
condition
eigentlich ist. Vermutlich muss es sich irgendwie ändern können, je nachdem, was sich im Array befindet.quelle
for
Aussage in mehrere Zeilen ist die beste Idee in dieser ganzen DiskussionEine Sache, die vergessen wurde: Wenn ich von einer Schleife abbreche (nicht alle möglichen Iterationen ausführen, egal wie implementiert), möchte ich in der Regel nicht nur die Schleife verlassen, sondern auch wissen, warum dies passiert ist . Wenn ich zum Beispiel nach einem Element X suche, breche ich nicht nur die Schleife ab, sondern möchte auch wissen, dass X gefunden wurde und wo es sich befindet.
In dieser Situation ist ein Zustand außerhalb der Schleife ganz natürlich. Also fange ich an mit
und in der Schleife werde ich schreiben
mit der for-Schleife
Jetzt ist es ganz natürlich, den Zustand in der Schleife zu überprüfen. Ob es eine "break" -Anweisung gibt, hängt davon ab, ob sich in der Schleife eine weitere Verarbeitung befindet, die Sie vermeiden möchten. Wenn ein Teil der Verarbeitung erforderlich ist und ein anderer Teil nicht, haben Sie möglicherweise etwas Ähnliches
irgendwo in deiner Schleife.
quelle