Ich bin vor einer Sekunde auf diese Frage gestoßen und ziehe einen Teil des Materials von dort ab: Gibt es einen Namen für das 'break n'-Konstrukt?
Dies scheint eine unnötig komplexe Möglichkeit zu sein, das Programm anweisen zu müssen, aus einer doppelt verschachtelten for-Schleife auszubrechen:
for (i = 0; i < 10; i++) {
bool broken = false;
for (j = 10; j > 0; j--) {
if (j == i) {
broken = true;
break;
}
}
if (broken)
break;
}
Ich weiß, dass Lehrbücher gerne sagen, dass goto-Aussagen der Teufel sind, und ich selbst mag sie überhaupt nicht, aber rechtfertigt dies eine Ausnahme von der Regel?
Ich suche nach Antworten, die sich mit n-geschachtelten for-Schleifen befassen.
HINWEIS: Unabhängig davon, ob Sie mit Ja, Nein oder irgendwo dazwischen antworten, sind völlig aufgeschlossene Antworten nicht erwünscht. Vor allem, wenn die Antwort Nein lautet, geben Sie einen guten, legitimen Grund dafür an (der ohnehin nicht zu weit von den Stack Exchange-Bestimmungen entfernt ist).
quelle
for (j = 10; j > 0 && !broken; j--)
brauchen Sie diebreak;
Anweisung nicht. Wenn Sie die Deklaration vonbroken
nach verschieben, bevor die äußere Schleife beginnt, dann, wenn das geschrieben werden könnte,for (i = 0; i < 10 && !broken; i++)
dann denke ich, dass keinebreak;
s notwendig sind.goto
: goto (C # -Referenz) - "Die goto-Anweisung ist auch nützlich, um tief verschachtelte Schleifen zu verlassen."goto
muss in einem C # -Schalter tatsächlich in einen anderen Fall übergehen, nachdem ein Code im ersten Fall ausgeführt wurde. Dies ist der einzige Fall, den ich bisher verwendet habe.Antworten:
Die offensichtliche Notwendigkeit einer Go-to-Anweisung entsteht, wenn Sie schlechte Bedingungsausdrücke für die Schleifen auswählen .
Sie geben an, dass die äußere Schleife so lange andauern soll
i < 10
und die innerste so lange andauern sollj > 0
.Aber in Wirklichkeit ist es nicht das, was Sie wollten . Sie haben den Loops einfach nicht den tatsächlichen Zustand mitgeteilt, den sie auswerten sollen, und Sie möchten ihn lösen, indem Sie break oder goto verwenden.
Wenn Sie den Loops von Anfang an Ihre wahren Absichten mitteilen , müssen Sie weder pausieren noch loslegen.
quelle
i
am Ende der äußeren Schleife gedruckt. Das Kurzschließen des Inkrements ist daher wichtig, damit der Code zu 100% äquivalent aussieht. Ich sage nicht, dass irgendetwas in Ihrer Antwort falsch ist, ich wollte nur darauf hinweisen, dass das sofortige Unterbrechen der Schleife ein wichtiger Aspekt des Codes war.i
am Ende der äußeren Schleife in der Frage von OP keinen Codedruck .goto
(ich bin sicher, es gibt bessere) bereitzustellen , auch wenn er eine Fragebreak(n)
aufwirft, die ihn als solche zu verwenden scheint, sondern um die grundlegende Aktion in Sprachen zu veranschaulichen, die dies nicht taten. nicht unterstützen.In diesem Fall könnten Sie den Code in eine separate Routine umgestalten und dann direkt
return
aus der inneren Schleife. Das würde die Notwendigkeit, aus der äußeren Schleife auszubrechen, zunichte machen:quelle
i
nach dem Ende der äußeren Schleife gedruckt . Um das wirklich zu reflektieren,i
ist das der wichtige Wert, hier sollte dasreturn true;
undreturn false;
beides seinreturn i;
.Nein, ich denke nicht, dass eine
goto
notwendig ist. Wenn du es so schreibst:Wenn Sie
&&!broken
beide Loops haben, können Sie aus beiden Loops ausbrechen, wenni==j
.Für mich ist dieser Ansatz vorzuziehen. Die Loop - Bedingungen sind sehr klar:
i<10 && !broken
.Eine funktionierende Version finden Sie hier: http://rextester.com/KFMH48414
Code:
Ausgabe:
quelle
broken
in Ihrem ersten Beispiel überhaupt ? Benutze einfach break auf der inneren Schlaufe. Auch, wenn Sie unbedingt verwenden müssenbroken
, warum deklarieren Sie es außerhalb der Schleifen? Erkläre es einfach in deri
Schleife. Was diewhile
Schleife anbelangt, verwenden Sie diese bitte nicht. Ich denke ehrlich, es schafft es, noch weniger lesbar zu sein als die goto-Version.broken
wird verwendet, weil ich diebreak
Anweisung nicht gerne benutze (außer bei switch-case, aber das war's auch schon). Es wird außerhalb der äußeren Schleife deklariert, falls Sie ALLE Schleifen unterbrechen möchten, wenni==j
. Sie haben Recht, im Allgemeinen mussbroken
nur vor der äußersten Schleife deklariert werden, dass sie unterbrochen wird.i==2
am Ende der Schleife. Die Erfolgsbedingung sollte auch das Inkrement kurzschließen, wenn es zu 100% a äquivalent sein sollbreak 2
.broken = (j == i)
es, wenn und wenn die Sprache es zulässt, die gebrochene Deklaration in die Initialisierung der äußeren Schleife einzufügen. Obwohl es schwierig ist, diese Dinge für dieses spezielle Beispiel zu sagen, da die gesamte Schleife ein No-Op ist (sie gibt nichts zurück und hat keine Nebenwirkungen) und wenn sie etwas tut, tut sie dies möglicherweise innerhalb des If (obwohl ich es immer nochbroken = (j ==i); if broken { something(); }
besser finde) persönlich)i
nach dem Ende der äußeren Schleife gedruckt . Mit anderen Worten, der einzige wirklich wichtige Gedanke ist, wann genau er aus der äußeren Schleife ausbricht.Die kurze Antwort lautet "es kommt darauf an". Ich befürworte, hinsichtlich der Lesbarkeit und Verständlichkeit Ihres Codes zu wählen. Der Weg dorthin ist möglicherweise besser lesbar, als die Bedingung zu ändern, oder umgekehrt. Sie können auch das Prinzip der geringsten Überraschung, die im Shop / Projekt verwendete Richtlinie und die Konsistenz der Codebasis berücksichtigen. Zum Beispiel ist es in der Linux-Kernel-Codebasis üblich, den Schalter zu verlassen oder Fehler zu behandeln. Beachten Sie auch, dass einige Programmierer möglicherweise Probleme haben, Ihren Code zu lesen (entweder mit dem Mantra "goto is evil" oder einfach nicht gelernt, weil ihr Lehrer dies denkt), und einige von ihnen könnten Sie sogar "beurteilen".
Im Allgemeinen ist es oft akzeptabel, in derselben Funktion weiterzugehen, insbesondere wenn der Sprung nicht zu lang ist. Ihr Anwendungsfall, eine verschachtelte Schleife zu verlassen, ist eines der bekannten Beispiele für "nicht so böse".
quelle
In Ihrem Fall ist goto eine Verbesserung genug, die verlockend wirkt, aber es ist nicht so sehr eine Verbesserung, dass es sich lohnt, die Regel gegen die Verwendung in Ihrer Codebasis zu brechen.
Denken Sie an Ihren zukünftigen Rezensenten: Er wird denken müssen: "Ist diese Person ein schlechter Kodierer oder ist dies tatsächlich ein Fall, in dem sich das Goto gelohnt hat? Lassen Sie mich 5 Minuten dauern, um dies für mich selbst zu entscheiden oder es auf der Website zu recherchieren Internet." Warum um alles in der Welt würden Sie das Ihrem zukünftigen Programmierer antun, wenn Sie goto nicht vollständig verwenden können?
Im Allgemeinen gilt diese Mentalität für jeden "schlechten" Code und definiert sie sogar: Wenn er jetzt funktioniert und in diesem Fall gut ist, aber Anstrengungen unternimmt, um zu überprüfen, ob er korrekt ist, was in dieser Ära ein Goto immer tun wird, dann nicht Tu es.
Davon abgesehen, ja, Sie haben einen der etwas dornigeren Fälle vorgelegt. Du darfst:
Es ist sehr schwer für mich, einen Fall zu schaffen, in dem ein Double-Loop nicht so zusammenhängend ist, dass es sowieso nicht seine eigene Routine sein sollte.
Die beste Diskussion, die ich je gesehen habe, ist übrigens Steve McConnells Code Complete . Wenn Sie gerne kritisch über diese Probleme nachdenken, empfehle ich nachdrücklich, sie zu lesen, auch wenn sie so unermesslich ist.
quelle
TLD; DR: Nein im Einzelnen, ja im Allgemeinen
Für das konkrete Beispiel, das Sie verwendet haben, würde ich aus den gleichen Gründen, auf die viele andere hingewiesen haben, Nein sagen. Sie können den Code auf einfache Weise in eine gleichwertige Form umgestalten, bei der das nicht mehr erforderlich ist
goto
.Im Allgemeinen ist das Verbot dagegen
goto
eine Allgemeinheit, die auf dem Verständnisgoto
und den Kosten ihrer Verwendung beruht . Ein Teil des Software-Engineerings besteht darin, Implementierungsentscheidungen zu treffen. Die Rechtfertigung dieser Entscheidungen erfolgt durch Abwägen der Kosten gegen den Nutzen und immer dann, wenn der Nutzen die Kosten überwiegt, ist die Umsetzung gerechtfertigt. Kontroversen ergeben sich aus unterschiedlichen Bewertungen von Kosten und Nutzen.Der Punkt ist, dass es immer Ausnahmen geben wird, in denen a
goto
gerechtfertigt ist, aber nur für einige aufgrund unterschiedlicher Bewertungen. Schade, dass viele Ingenieure Techniken in absichtlicher Ignoranz einfach ausschließen, weil sie sie im Internet lesen, anstatt sich die Zeit zu nehmen, um zu verstehen, warum.quelle
Ich glaube nicht, dass dieser Fall eine Ausnahme rechtfertigt, da dies wie folgt geschrieben werden kann:
quelle