Betrachten Sie den folgenden Code:
public void doSomething(int input)
{
while(true)
{
TransformInSomeWay(input);
if(ProcessingComplete(input))
break;
DoSomethingElseTo(input);
}
}
Angenommen, dieser Prozess beinhaltet eine endliche, aber eingabeabhängige Anzahl von Schritten. Die Schleife ist so konzipiert, dass sie aufgrund des Algorithmus von selbst endet und nicht auf unbestimmte Zeit ausgeführt wird (bis sie durch ein externes Ereignis abgebrochen wird). Da sich der Test, ob die Schleife enden soll, in der Mitte einer logischen Reihe von Schritten befindet, überprüft die while-Schleife selbst derzeit nichts Sinnvolles. Die Prüfung wird stattdessen an der "richtigen" Stelle innerhalb des konzeptionellen Algorithmus durchgeführt.
Mir wurde gesagt, dass dies ein fehlerhafter Code ist, da er aufgrund der Endbedingung, die von der Schleifenstruktur nicht überprüft wird, fehleranfälliger ist. Es ist schwieriger herauszufinden, wie Sie die Schleife verlassen würden, und es kann zu Fehlern kommen, da die Unterbrechungsbedingung möglicherweise umgangen oder bei zukünftigen Änderungen versehentlich weggelassen wird.
Der Code könnte nun folgendermaßen aufgebaut sein:
public void doSomething(int input)
{
TransformInSomeWay(input);
while(!ProcessingComplete(input))
{
DoSomethingElseTo(input);
TransformInSomeWay(input);
}
}
Dies dupliziert jedoch einen Aufruf einer Methode im Code, wodurch DRY verletzt wird. Wenn TransformInSomeWay
sie später durch eine andere Methode ersetzt würden, müssten beide Aufrufe gefunden und geändert werden (und die Tatsache, dass es zwei gibt, ist in einem komplexeren Codeteil möglicherweise weniger offensichtlich).
Sie könnten es auch so schreiben:
public void doSomething(int input)
{
var complete = false;
while(!complete)
{
TransformInSomeWay(input);
complete = ProcessingComplete(input);
if(!complete)
{
DoSomethingElseTo(input);
}
}
}
... aber Sie haben jetzt eine Variable, deren einziger Zweck darin besteht, die Bedingungsüberprüfung auf die Schleifenstruktur zu verschieben, und die außerdem mehrmals überprüft werden muss, um dasselbe Verhalten wie die ursprüngliche Logik zu erzielen.
Ich für meinen Teil sage, dass angesichts des Algorithmus, den dieser Code in der realen Welt implementiert, der Originalcode am besten lesbar ist. Wenn Sie es selbst durchgehen würden, würden Sie so darüber nachdenken, und daher wäre es für Leute, die mit dem Algorithmus vertraut sind, intuitiv.
Also, was ist "besser"? Ist es besser, die Zustandsüberprüfung der while-Schleife zu übertragen, indem die Logik um die Schleife herum strukturiert wird? Oder ist es besser, die Logik auf "natürliche" Weise zu strukturieren, wie dies durch Anforderungen oder eine konzeptionelle Beschreibung des Algorithmus angezeigt wird, obwohl dies bedeuten kann, dass die eingebauten Funktionen der Schleife umgangen werden?
do ... until
Konstrukt ist auch für diese Art von Schleifen nützlich, da sie nicht "grundiert" werden müssen.Antworten:
Bleiben Sie bei Ihrer ersten Lösung. Schleifen können sehr kompliziert werden und eine oder mehrere saubere Unterbrechungen können für Sie, jeden anderen, der sich Ihren Code, das Optimierungsprogramm und die Leistung des Programms ansieht, viel einfacher sein als aufwändige if-Anweisungen und hinzugefügte Variablen. Mein üblicher Ansatz ist es, eine Schleife mit so etwas wie "while (true)" zu erstellen und die bestmögliche Codierung zu erhalten. Oft kann und kann ich dann die Unterbrechung (en) durch eine Standardschleifensteuerung ersetzen; Schließlich sind die meisten Loops ziemlich einfach. Die Endbedingung sollte durch die Schleifenstruktur für die Gründe überprüft werden Sie erwähnen, aber nicht auf Kosten der Zugabe von ganz neuen Variablen, Hinzufügen if-Anweisungen und sich wiederholende Code, alle sind noch mehr Fehler anfällig.
quelle
Es ist nur dann ein bedeutungsvolles Problem, wenn der Schleifenkörper nicht trivial ist. Wenn der Körper so klein ist, ist die Analyse so trivial und überhaupt kein Problem.
quelle
Ich habe Probleme, die anderen Lösungen besser zu finden als die mit Pause. Nun, ich bevorzuge den Ada-Weg, der das erlaubt
aber die break-lösung ist das sauberste rendern.
Mein POV ist, dass, wenn eine Kontrollstruktur fehlt, die sauberste Lösung darin besteht, sie mit anderen Kontrollstrukturen zu emulieren, ohne den Datenfluss zu verwenden. (Und in ähnlicher Weise, wenn ich ein Datenflussproblem habe und reine Datenflusslösungen gegenüber einer Lösung mit Kontrollstrukturen vorziehen möchte *).
Verwechseln Sie sich nicht, die Diskussion würde nicht stattfinden, wenn die Schwierigkeit nicht zum größten Teil gleich wäre: Der Zustand ist derselbe und am selben Ort vorhanden.
Welche von
und
die beabsichtigte Struktur besser machen? Ich stimme für die erste, Sie müssen nicht überprüfen, ob die Bedingungen übereinstimmen. (Aber siehe meine Einrückung).
quelle
while (wahr) und break ist eine verbreitete Redewendung. Dies ist die kanonische Methode, um Mid-Exit-Schleifen in C-ähnlichen Sprachen zu implementieren. Das Hinzufügen einer Variablen zum Speichern der Ausgangsbedingung und eines if () in der zweiten Hälfte der Schleife ist eine sinnvolle Alternative. Einige Läden mögen die eine oder andere offiziell standardisieren, aber keine ist überlegen; sie sind gleichwertig.
Ein guter Programmierer, der in diesen Sprachen arbeitet, sollte wissen können, was auf einen Blick vor sich geht, wenn er eine der beiden Sprachen sieht. Es könnte eine gute kleine Interviewfrage sein; Hand jemand zwei Schleifen, eine mit jeder Redewendung, und frage ihn, was der Unterschied ist (richtige Antwort: "nichts", mit vielleicht einem Zusatz von "aber ich benutze gewohnheitsmäßig DIESE.")
quelle
Ihre Alternativen sind nicht so schlecht, wie Sie vielleicht denken. Guter Code sollte:
Geben Sie mit guten Variablennamen / Kommentaren deutlich an, unter welchen Bedingungen die Schleife beendet werden soll. (Die Bruchbedingung sollte nicht verborgen sein)
Geben Sie klar an, in welcher Reihenfolge die Operationen ausgeführt werden sollen. Hier ist
DoSomethingElseTo(input)
es eine gute Idee , die optionale dritte Operation ( ) in das if zu setzen.Das heißt, es ist leicht, perfektionistische, messingpolierende Instinkte viel Zeit in Anspruch nehmen zu lassen. Ich würde nur die Einstellungen anpassen, wenn dies oben erwähnt wurde. Kommentieren Sie den Code und fahren Sie fort.
quelle
Die Leute sagen, es sei eine schlechte Übung
while (true)
, und die meiste Zeit haben sie Recht. Wenn Ihrewhile
Anweisung viele komplizierte Codes enthält und es unklar ist, wann Sie aus if ausbrechen, bleibt Ihnen schwer zu pflegender Code und ein einfacher Fehler kann eine Endlosschleife verursachen.In Ihrem Beispiel ist die Verwendung korrekt,
while(true)
da Ihr Code klar und leicht verständlich ist. Es hat keinen Sinn, ineffizienten und schwerer lesbaren Code zu erstellen, nur weil manche Leute es für immer schlecht halten, ihn zu verwendenwhile(true)
.Ich hatte ein ähnliches Problem:
Durch
do ... while(true)
die Verwendung von wird vermieden, dassisset($array][$key]
unnötigerweise zweimal aufgerufen wird. Der Code ist kürzer, übersichtlicher und einfacher zu lesen. Es besteht absolut keine Gefahr, dasselse break;
am Ende ein Endlosschleifen-Fehler auftritt .Es ist gut, guten Praktiken zu folgen und schlechte Praktiken zu vermeiden , aber es gibt immer Ausnahmen, und es ist wichtig, offen zu bleiben und diese Ausnahmen zu erkennen.
quelle
Wenn ein bestimmter Steuerungsfluss auf natürliche Weise als break-Anweisung ausgedrückt wird, ist es grundsätzlich nie besser, andere Flusssteuerungsmechanismen zum Emulieren einer break-Anweisung zu verwenden.
(Beachten Sie, dass dies das teilweise Abrollen der Schleife und das Herunterrutschen des Schleifenkörpers umfasst, so dass der Beginn der Schleife mit dem bedingten Test übereinstimmt.)
Wenn Sie Ihre Schleife so reorganisieren können, dass der Kontrollfluss natürlich durch eine bedingte Prüfung am Anfang der Schleife ausgedrückt wird, ist das großartig. Es könnte sich sogar lohnen, sich Gedanken darüber zu machen, ob dies möglich ist. Versuchen Sie aber nicht, einen quadratischen Stift in ein rundes Loch zu stecken.
quelle
Sie könnten auch damit gehen:
Oder weniger verwirrend:
quelle
Wenn die Komplexität der Logik unhandlich wird, ist die Verwendung einer unbegrenzten Schleife mit Unterbrechungen in der Mitte der Schleife zur Flusssteuerung tatsächlich am sinnvollsten. Ich habe ein Projekt mit einem Code, der wie folgt aussieht. (Beachten Sie die Ausnahme am Ende der Schleife.)
Um diese Logik ohne uneingeschränkte Unterbrechung der Schleife auszuführen, würde ich am Ende etwa Folgendes erhalten:
Die Ausnahme wird jetzt in einer Hilfsmethode ausgelöst. Es hat auch ziemlich viel
if ... else
Nesting. Ich bin mit diesem Ansatz nicht zufrieden. Daher finde ich das erste Muster am besten.quelle