Wer hat entschieden (und basierend auf welchen Konzepten), dass die switch
Konstruktion (in vielen Sprachen) break
in jeder Anweisung verwendet werden muss?
Warum müssen wir so etwas schreiben:
switch(a)
{
case 1:
result = 'one';
break;
case 2:
result = 'two';
break;
default:
result = 'not determined';
break;
}
(Dies ist in PHP und JS aufgefallen. Es gibt wahrscheinlich viele andere Sprachen, die dies verwenden.)
Wenn switch
ist eine Alternative von if
, warum können wir nicht die gleiche Konstruktion wie für verwenden if
? Dh:
switch(a)
{
case 1:
{
result = 'one';
}
case 2:
{
result = 'two';
}
default:
{
result = 'not determined';
}
}
Es wird gesagt, break
dass die Ausführung des Blocks nach dem aktuellen verhindert wird. Aber ist jemand wirklich in die Situation geraten, in der die Ausführung des aktuellen und der folgenden Blöcke erforderlich war? Habe ich nicht. Für mich break
ist immer da. In jedem Block. In jedem Code.
conditions
trejder
quelle
quelle
CASE
Anweisung gleichwertig mit einem riesigen if / elseif-Block.case 'a': case 'A': case 'b': case 'B'
aber meistens gemacht weil ich das nicht kanncase in [ 'a', 'A', 'b', 'B' ]
. Eine etwas bessere Frage ist, dass in meiner derzeit bevorzugten Sprache (C #) die Unterbrechung obligatorisch ist und es keinen impliziten Sturz gibt. Vergessenbreak
ist ein Syntaxfehler ...: \case TOKEN_A: /*set flag*/; case TOKEN_B: /*consume token*/; break; case TOKEN_C: /*...*/
break
irgendwo vorhanden ist" ist eine wesentlich einfachere Regel als "Einen Sprung nicht ausgeben, wenn erfallthrough
in a vorhanden istswitch
".Antworten:
C war eine der ersten Sprachen, die diese
switch
Aussage in dieser Form erhalten hat, und alle anderen wichtigen Sprachen haben sie von dort geerbt. Sie haben sich hauptsächlich dafür entschieden, die C-Semantik standardmäßig beizubehalten - sie haben entweder nicht über die Vorteile einer Änderung nachgedacht oder beurteilt Sie sind weniger wichtig als das Verhalten, an das jeder gewöhnt war.Warum C so entworfen wurde, ist wahrscheinlich auf das Konzept von C als "tragbare Baugruppe" zurückzuführen. Die
switch
Anweisung ist im Grunde eine Abstraktion einer Verzweigungstabelle , und eine Verzweigungstabelle hat auch einen impliziten Durchbruch und erfordert eine zusätzliche Sprunganweisung, um diesen zu vermeiden.Daher haben die Designer von C auch beschlossen, die Assemblersemantik standardmäßig beizubehalten.
quelle
switchon
.when
.Denn
switch
ist keine Alternative zuif ... else
Aussagen in diesen Sprachen.Durch die Verwendung von
switch
können wir mehr als eine Bedingung gleichzeitig erfüllen, was in einigen Fällen sehr geschätzt wird.Beispiel:
quelle
more than one block ... unwanted in most cases
Ich stimme dir nicht zu.break
. Aber ja, soweit mir bekannt ist, funktioniert Duffs Gerät in C # nicht.C# does not support an implicit fall through from one case label to another
. Sie können durchfallen, aber es gibt keine Chance, versehentlich eine Pause zu vergessen.if..else
aber in einigen Situationenswitch..case
wäre vorzuziehen. Das obige Beispiel wäre etwas komplex, wenn wir if-else verwenden würden.Dies wurde bei Stack Overflow im Zusammenhang mit C gefragt: Warum sollte die switch-Anweisung eine Unterbrechung benötigen?
Um die akzeptierte Antwort zusammenzufassen, war es wahrscheinlich ein Fehler. Die meisten anderen Sprachen sind wahrscheinlich gerade erst C gefolgt. Einige Sprachen wie C # scheinen dies jedoch durch das Zulassen von Ausfällen behoben zu haben - aber nur, wenn der Programmierer dies ausdrücklich mitteilt (Quelle: der obige Link, ich spreche kein C # selbst). .
quelle
/* FALLTHRU */
Kommentar in der Antwort, die von @Tapio oben verlinkt wurde, um zu beweisen, dass Sie es gemeint haben.goto case
wie der Link funktioniert, lässt sich nicht veranschaulichen, warum dies so gut funktioniert. Sie können immer noch mehrere Fälle wie oben stapeln, aber sobald Sie Code einfügen, müssen Sie einen expliziten Code haben, umgoto case whatever
zum nächsten Fall überzugehen, oder Sie erhalten einen Compilerfehler. Wenn Sie mich befragen, ist die Möglichkeit, Fälle zu stapeln, ohne sich Gedanken über versehentliches Durchfallen durch Nachlässigkeit zu machen, bei weitem besser, als das explizite Durchfallen mit zu ermöglichengoto case
.Ich werde mit einem Beispiel antworten. Wenn Sie die Anzahl der Tage für jeden Monat eines Jahres auflisten möchten, ist es offensichtlich, dass einige Monate 31, 30 und 1 28/29 haben. Es würde so aussehen,
Dies ist ein Beispiel, in dem mehrere Fälle den gleichen Effekt haben und alle zusammen gruppiert sind. Es gab offensichtlich einen Grund für die Wahl des Schlüsselworts break und nicht das if ... else if- Konstrukt.
Das Wichtigste dabei ist, dass eine switch- Anweisung mit vielen ähnlichen Fällen kein if ... else if ... else if ... else für jeden der Fälle ist, sondern if (1, 2, 3) ... sonst wenn (4,5,6) sonst ...
quelle
if
ohne Nutzen. Wäre es vielleicht sinnvoller, wenn Ihrem Beispiel ein Name zugewiesen würde oder zusätzlich zum Fall-through eine monatenspezifische Arbeit geleistet würde? (ohne zu kommentieren, ob man überhaupt sollte)Es gibt zwei Situationen, in denen von einem Fall zum anderen „durchgefallen“ werden kann - der leere Fall:
und der nicht leere Fall
Ungeachtet des Verweises auf Duffs Gerät gibt es nur wenige legitime Fälle für den zweiten Fall, die im Allgemeinen durch Kodierungsstandards verboten und während der statischen Analyse gekennzeichnet sind. Und wo es gefunden wird, ist es meistens auf das Weglassen von a zurückzuführen
break
.Ersteres ist durchaus sinnvoll und üblich.
Um ehrlich zu sein, sehe ich keinen Grund, den
break
und den Sprachparser zu brauchen, der weiß, dass ein leerer Fallkörper ein Durchbruch ist, während ein nicht leerer Fall ein eigenständiger Fall ist.Es ist schade, dass das ISO-C-Panel mehr damit beschäftigt zu sein scheint, der Sprache neue (unerwünschte) und schlecht definierte Features hinzuzufügen, als die undefinierten, nicht spezifizierten oder implementierungsdefinierten Features zu reparieren, ganz zu schweigen von den unlogischen.
quelle
Nicht erzwingen
break
erlaubt eine Reihe von Dingen, die sonst schwierig zu tun sein könnten. Andere haben Gruppierungsfälle festgestellt, für die es eine Reihe nicht trivialer Fälle gibt.Ein Fall, in dem es unbedingt erforderlich ist, dass das
break
nicht verwendet wird, ist Duff's Device . Dies wird zum " Aufrollen " von Schleifen verwendet, um Operationen zu beschleunigen, indem die Anzahl der erforderlichen Vergleiche begrenzt wird. Ich glaube, die anfängliche Verwendung ermöglichte Funktionen, die zuvor mit einer vollständig aufgerollten Schleife zu langsam waren. In einigen Fällen wird die Codegröße gegen die Geschwindigkeit eingetauscht.Es ist empfehlenswert, das Symbol
break
durch einen entsprechenden Kommentar zu ersetzen , wenn der Fall einen Code enthält. Andernfalls wird jemand das Fehlen behebenbreak
und einen Fehler einführen.quelle
In C, wo der Ursprung zu sein scheint, ist der Codeblock der
switch
Anweisung kein spezielles Konstrukt. Es ist ein normaler Codeblock, genau wie ein Block unter einerif
Anweisung.case
unddefault
sind Sprungmarken in diesem Block, die sich speziell auf beziehenswitch
. Sie werden genauso behandelt wie normale Sprungmarken fürgoto
. Hierbei ist eine bestimmte Regel wichtig: Sprungmarken können sich fast überall im Code befinden, ohne den Codefluss zu unterbrechen.Als normaler Codeblock muss es sich nicht um eine zusammengesetzte Anweisung handeln. Die Bezeichnungen sind ebenfalls optional. Dies sind gültige
switch
Aussagen in C:Der C-Standard selbst gibt dies als Beispiel an (6.8.4.2):
Darüber hinaus
default
handelt es sich auch um eine Sprungmarke und kann somit überall sein, ohne dass der letzte Fall vorliegen muss.Dies erklärt auch Duffs Gerät:
Warum der Durchfall? Da im normalen Codefluss in einem normalen Codeblock ein Durchreichen der nächsten Anweisung erwartet wird , wie Sie es in einem
if
Codeblock erwarten würden .Ich vermute, dass der Grund dafür die einfache Implementierung war. Sie benötigen keinen speziellen Code zum Parsen und Kompilieren eines
switch
Blocks, der spezielle Regeln berücksichtigt . Sie analysieren es einfach wie jeden anderen Code und müssen sich nur um die Bezeichnungen und die Sprungauswahl kümmern.Eine interessante Folgefrage ist, ob die folgenden verschachtelten Anweisungen "Done" ausgeben. oder nicht.
Dafür sorgt der C-Standard (6.8.4.2.4):
quelle
Einige Leute haben bereits den Begriff der Übereinstimmung mehrerer Bedingungen erwähnt, der von Zeit zu Zeit sehr wertvoll ist. Die Fähigkeit, mehrere Bedingungen zu erfüllen, erfordert jedoch nicht unbedingt, dass Sie für jede Bedingung, die erfüllt ist, genau dasselbe tun. Folgendes berücksichtigen:
Es gibt zwei verschiedene Arten, wie Gruppen von mehreren Bedingungen hier abgeglichen werden. Mit den Bedingungen 1 und 2 fallen sie einfach auf genau den gleichen Code durch und tun genau das Gleiche. Mit Bedingungen 3 und 4 jedoch, obwohl sie beide Ende durch den Aufruf
doSomething3And4()
, nur 3 AnrufedoSomething3()
.quelle
case 2
Auslösen führen können. Wenn wir also richtig sein wollen (und wir tun es), dann ist das real Funktionsname müsste seindoSomethingBecause_1_OR_2_OR_1AND2()
oder so (obwohl legitimer Code, in dem eine unveränderliche Datei zwei verschiedenen Fällen entspricht, während noch gut geschriebener Code praktisch nicht vorhanden ist, sollte dies zumindest seindoSomethingBecause1or2()
)doSomething[ThatShouldBeDoneInTheCaseOf]1And[InTheCaseOf]2()
. Es bezieht sich nicht auf logische und / oder.Um zwei Ihrer Fragen zu beantworten.
Warum braucht C Pausen?
Als "portabler Assembler" kommt es auf Cs-Roots an. Wo Psudo-Code wie dieser üblich war: -
Die switch-Anweisung wurde entwickelt, um ähnliche Funktionen auf einer höheren Ebene bereitzustellen.
Haben wir jemals Schalter ohne Unterbrechungen?
Ja, das ist ziemlich häufig und es gibt einige Anwendungsfälle.
Zunächst möchten Sie möglicherweise in mehreren Fällen die gleiche Aktion ausführen. Wir tun dies, indem wir die Hüllen aufeinander stapeln:
Ein weiterer in Zustandsautomaten üblicher Anwendungsfall ist, dass wir nach der Verarbeitung eines Zustands sofort in einen anderen Zustand eintreten und diesen verarbeiten möchten:
quelle
Die Anweisung break ist eine Sprunganweisung, mit der der Benutzer den nächstgelegenen umschließenden Schalter (für Ihren Fall) verlassen kann, während, do, for oder foreach ausgeführt wird. es ist genauso einfach.
quelle
Ich denke, dass mit allen oben beschriebenen - das Hauptergebnis dieses Threads ist, dass, wenn Sie eine neue Sprache entwerfen - die Standardeinstellung sein sollte, dass Sie keine
break
Anweisung hinzufügen müssen und der Compiler sie so behandelt, als ob Sie es getan hätten.Wenn Sie diesen seltenen Fall möchten, in dem Sie mit dem nächsten Fall fortfahren möchten, geben Sie ihn einfach mit einer
continue
Erklärung an.Dies kann so verbessert werden, dass nur dann, wenn Sie geschweifte Klammern im Inneren des Gehäuses verwenden, dies nicht weitergeht, sodass das Beispiel mit den obigen Monaten von mehreren Fällen, in denen derselbe exakte Code ausgeführt wird, immer wie erwartet funktioniert, ohne dass der Code benötigt wird
continue
.quelle
*
,&
,static
usw.