In einer meiner ersten Codeüberprüfungen (vor einiger Zeit) wurde mir gesagt, dass es empfehlenswert ist, eine Standardklausel in alle switch-Anweisungen aufzunehmen. Ich habe mich kürzlich an diesen Rat erinnert, kann mich aber nicht erinnern, was die Rechtfertigung war. Es klingt jetzt ziemlich seltsam für mich.
Gibt es einen vernünftigen Grund, immer eine Standardanweisung einzuschließen?
Ist diese Sprache abhängig? Ich kann mich nicht erinnern, welche Sprache ich damals verwendet habe - vielleicht gilt dies für einige Sprachen und nicht für andere?
default
switch-statement
tttppp
quelle
quelle
Antworten:
Switch Cases sollten fast immer einen
default
Case haben.Gründe für die Verwendung von a
default
1.Um einen unerwarteten Wert zu "fangen"
2. Um 'Standard'-Aktionen zu behandeln, bei denen es sich um besondere Verhaltensweisen handelt.
Sie sehen dies VIEL in menügesteuerten Programmen und Bash-Shell-Skripten. Dies wird möglicherweise auch angezeigt, wenn eine Variable außerhalb des Switch-Falls deklariert, aber nicht initialisiert wird und in jedem Fall auf etwas anderes initialisiert wird. Hier muss die Standardeinstellung ebenfalls initialisiert werden, damit der Zeilencode, der auf die Variable zugreift, keinen Fehler auslöst.
3. Um jemandem, der Ihren Code liest, zu zeigen, dass Sie diesen Fall behandelt haben.
Dies war ein stark vereinfachtes Beispiel, aber der Punkt ist, dass sich jemand, der den Code liest, nicht fragen sollte, warum er
variable
nicht etwas anderes als 1 oder 2 sein kann.Der einzige Fall, den ich mir vorstellen kann , NICHT zu verwenden,
default
ist, wenn der Schalter etwas überprüft, bei dem es ziemlich offensichtlich ist, dass jede andere Alternative glücklich ignoriert werden kannquelle
enum MyEnum { FOO = 0, BAR = 1 }; MyEnum value = (MyEnum)2;
wird eine gültigeMyEnum
Instanz erstellt, die nicht gleichFOO
oder istBAR
. Wenn eines dieser Probleme einen Fehler in Ihrem Projekt verursachen würde, hilft Ihnen ein Standardfall dabei, den Fehler sehr schnell zu finden, häufig ohne dass ein Debugger erforderlich ist!Nein.
Was ist, wenn es keine Standardaktion gibt? Der Kontext ist wichtig. Was ist, wenn Sie nur auf wenige Werte reagieren möchten?
Nehmen Sie das Beispiel des Lesens von Tastendrücken für ein Spiel
Hinzufügen:
Ist nur Zeitverschwendung und erhöht die Komplexität des Codes ohne Grund.
quelle
// do nothing
Kommentar jedoch deutlich, dass es "in Ordnung" ist, wenn nicht alle Fälle abgedeckt sind, im Gegensatz zu anderen switch-Anweisungen, bei denen dies "nicht in Ordnung" wäre.In einigen Situationen kann es tatsächlich von Vorteil sein, NICHT den Standardfall zu haben.
Wenn es sich bei Ihren Switch-Fällen um Aufzählungswerte handelt und Sie keinen Standardfall haben, können Sie eine Compiler-Warnung erhalten, wenn Sie Fälle vermissen. Auf diese Weise können Sie sich beim Kompilieren über das Problem informieren, wenn in Zukunft neue Aufzählungswerte hinzugefügt werden und Sie vergessen, Fälle für diese Werte im Switch hinzuzufügen. Sie sollten weiterhin sicherstellen, dass der Code geeignete Maßnahmen für nicht behandelte Werte ergreift, falls ein ungültiger Wert in den Aufzählungstyp umgewandelt wurde. Dies funktioniert also am besten in einfachen Fällen, in denen Sie innerhalb des Enum-Falls zurückkehren können, anstatt zu brechen.
quelle
Ich würde immer eine Standardklausel verwenden, egal in welcher Sprache Sie arbeiten.
Dinge können und können schief gehen. Werte werden nicht das sein, was Sie erwarten, und so weiter.
Wenn Sie keine Standardklausel einfügen möchten, können Sie sicher sein, dass Sie die möglichen Werte kennen. Wenn Sie glauben, die Menge der möglichen Werte zu kennen, möchten Sie darüber informiert werden, wenn der Wert außerhalb dieser Menge möglicher Werte liegt - es ist sicherlich ein Fehler.
Aus diesem Grund sollten Sie immer eine Standardklausel verwenden und einen Fehler auslösen, beispielsweise in Java:
Es gibt keinen Grund, mehr Informationen als nur die "nicht erreichbare" Zeichenfolge anzugeben. Wenn dies tatsächlich passiert, müssen Sie sich ohnehin die Quelle und die Werte der Variablen usw. ansehen, und die Ausnahmestapelverfolgung enthält diese Zeilennummer, sodass Sie keine Zeit damit verschwenden müssen, mehr Text in die Ausnahmemeldung zu schreiben.
quelle
throw new RuntimeException("myVar invalid " + myVar);
da dies Ihnen möglicherweise genügend Informationen liefert, um den Fehler herauszufinden und zu beheben, ohne einen Debugger verwenden und Variablen untersuchen zu müssen. Dies kann schwierig sein, wenn dies ein selten auftretendes Problem ist, das schwer zu reproduzieren ist.default:
. Aber meistens lässt man einen Standard weg, weil man denkt, dass ermyVar
niemals einen anderen Wert als den aufgelisteten haben kann; Ich kann jedoch nicht zählen, wie oft ich im wirklichen Leben überrascht war, als die Variable einen anderen Wert hatte als die Werte, die sie "möglicherweise" haben könnte. In diesen Fällen war ich dankbar für die Ausnahme, die mich sofort erkennen ließ, anstatt später einen anderen Fehler (schwieriger zu debuggen) oder eine falsche Antwort (wird beim Testen möglicherweise übersehen) zu verursachen.AssertionError
statt zu werfenRuntimeException
, da diese Situation einer Behauptung sehr ähnlich ist, die besagt, dass diesmyVar
einer der behandelten Werte ist. Auch die Wahrscheinlichkeit, dass jemand den Fehler fängt und verschluckt, ist geringer.In meinem Unternehmen schreiben wir Software für den Avionik- und Verteidigungsmarkt und fügen immer eine Standardanweisung hinzu, da ALLE Fälle in einer switch-Anweisung explizit behandelt werden müssen (auch wenn es sich nur um einen Kommentar mit der Aufschrift "Nichts tun" handelt). Wir können es uns nicht leisten, dass sich die Software nur schlecht verhält oder bei unerwarteten (oder sogar für unmöglich gehaltenen) Werten abstürzt.
Es kann diskutiert werden, dass ein Standardfall nicht immer notwendig ist, aber indem er immer benötigt wird, kann er von unseren Codeanalysatoren leicht überprüft werden.
quelle
Sollte eine "switch" -Anweisung immer eine Standardklausel enthalten? Nein, sollte es normalerweise eine Standardeinstellung enthalten.
Das Einfügen einer Standardklausel ist nur dann sinnvoll, wenn etwas zu tun ist, z. B. eine Fehlerbedingung geltend zu machen oder ein Standardverhalten bereitzustellen. Das Einschließen eines "nur weil" ist eine Frachtkult-Programmierung und bietet keinen Wert. Es ist das "switch" -Äquivalent zu der Aussage, dass alle "if" -Anweisungen ein "else" enthalten sollten.
Hier ist ein triviales Beispiel dafür, wo es keinen Sinn macht:
Dies entspricht:
quelle
default:
in diesen Fällen kodifiziert Ihre Annahmen. Ist es beispielsweise in Ordnung, wannsgn==0
gedruckt werden sollinteger
(weder positiv noch negativ), oder ist das ein Fehler? Für mich ist es schwer zu sagen, diesen Code zu lesen. Ich würde annehmen, dass Siezero
in diesem Fall nicht schreiben möchteninteger
und dass der Programmierer die Annahme getroffen hat, dasssgn
nur -1 oder +1 sein kann. Wenn dies der Falldefault:
wäre, könnte der Programmierer den Annahmefehler frühzeitig erkennen und den Code ändern.Soweit ich es sehe, ist die Antwort "Standard" optional. Die Aussage, dass ein Schalter immer eine Standardeinstellung enthalten muss, ist wie die Aussage, dass jedes "if-elseif" ein "else" enthalten muss. Wenn standardmäßig eine Logik ausgeführt werden muss, sollte die Anweisung 'default' vorhanden sein. Andernfalls kann der Code weiterhin ausgeführt werden, ohne dass etwas unternommen wird.
quelle
Eine Standardklausel zu haben, wenn sie nicht wirklich benötigt wird, ist defensive Programmierung. Dies führt normalerweise zu Code, der aufgrund von zu viel Fehlerbehandlungscode zu komplex ist. Dieser Fehlerbehandlungs- und Erkennungscode beeinträchtigt die Lesbarkeit des Codes, erschwert die Wartung und führt schließlich zu mehr Fehlern als behoben.
Ich glaube also, wenn der Standard nicht erreicht werden sollte, müssen Sie ihn nicht hinzufügen.
Beachten Sie, dass "sollte nicht erreicht werden" bedeutet, dass es ein Fehler in der Software ist, wenn es erreicht wird. Sie müssen Werte testen, die aufgrund von Benutzereingaben usw. unerwünschte Werte enthalten können.
quelle
Ich würde sagen, es hängt von der Sprache ab, aber in C ist es wahrscheinlich besser, wenn Sie einen Aufzählungstyp einschalten und jeden möglichen Wert verarbeiten, KEINEN Standardfall einzuschließen. Auf diese Weise gibt Ihnen ein kompetenter Compiler eine Warnung über den fehlenden Fall, wenn Sie später ein zusätzliches Enum-Tag hinzufügen und vergessen, es dem Switch hinzuzufügen.
quelle
gcc -Wall
(Art des kleinsten gemeinsamen Nenners kompetenter Compiler) gibt Warnungen vor Aufzählungen aus, die in switch-Anweisungen nicht behandelt werden.Wenn Sie wissen, dass die switch-Anweisung immer nur einen streng definierten Satz von Beschriftungen oder Werten enthält, tun Sie dies einfach, um die Basen abzudecken. Auf diese Weise erhalten Sie immer ein gültiges Ergebnis. Setzen Sie einfach die Standardeinstellung über die Beschriftung, die programmgesteuert / logisch wäre Seien Sie der beste Handler für andere Werte.
quelle
default
noch benötigt? Oder erlaubt dies eine spezielle Syntax, mit der Sie sie weglassen konnten?Zumindest ist es in Java nicht obligatorisch. Laut JLS kann höchstens ein Standardfall vorliegen. Dies bedeutet, dass kein Standardfall akzeptabel ist. Es hängt manchmal auch vom Kontext ab, in dem Sie die switch-Anweisung verwenden. In Java beispielsweise erfordert der folgende Switch-Block keinen Standardfall
Bei der folgenden Methode, bei der erwartet wird, dass ein String zurückgegeben wird, ist der Standardfall hilfreich, um Kompilierungsfehler zu vermeiden
Sie können zwar Kompilierungsfehler für die oben beschriebene Methode vermeiden, ohne einen Standardfall zu haben, indem Sie am Ende nur eine return-Anweisung haben. Wenn Sie jedoch einen Standardfall angeben, wird diese besser lesbar.
quelle
Einige (veraltete) Richtlinien sagen dies, wie beispielsweise MISRA C :
Dieser Rat ist veraltet, da er nicht auf derzeit relevanten Kriterien basiert. Die krasse Auslassung war das, was Harlan Kassler sagte:
Wenn Sie den Standardfall weglassen, kann der Compiler optional warnen oder fehlschlagen, wenn ein nicht behandelter Fall angezeigt wird. Die statische Überprüfbarkeit ist schließlich besser als jede dynamische Prüfung und daher kein würdiges Opfer, wenn Sie auch die dynamische Prüfung benötigen.
Wie Harlan ebenfalls demonstrierte, kann das funktionale Äquivalent eines Standardfalls nach dem Wechsel neu erstellt werden. Was trivial ist, wenn jeder Fall eine vorzeitige Rückkehr ist.
Die typische Notwendigkeit einer dynamischen Prüfung ist im weitesten Sinne die Eingabebehandlung. Wenn ein Wert außerhalb der Kontrolle des Programms liegt, kann er nicht als vertrauenswürdig eingestuft werden.
Hier vertritt Misra auch den Standpunkt einer extrem defensiven Programmierung. Solange ein ungültiger Wert physisch darstellbar ist, muss er überprüft werden, unabhängig davon, ob das Programm nachweislich korrekt ist. Dies ist sinnvoll, wenn die Software bei Hardwarefehlern so zuverlässig wie möglich sein muss. Aber wie Ophir Yoktan sagte, ist es für die meisten Software besser, Fehler nicht zu "behandeln". Die letztere Praxis wird manchmal als anstößige Programmierung bezeichnet .
quelle
Sie sollten eine Standardeinstellung haben, um unerwartete Werte abzufangen.
Ich bin jedoch nicht mit Adrian Smith einverstanden, dass Ihre Standardfehlermeldung etwas völlig Bedeutungsloses sein sollte. Möglicherweise gibt es einen nicht behandelten Fall, den Sie nicht vorhergesehen haben (was der Punkt ist), den Ihr Benutzer am Ende sehen wird, und eine Nachricht wie "nicht erreichbar" ist völlig sinnlos und hilft niemandem in dieser Situation.
Wie oft hatten Sie ein völlig bedeutungsloses BSOD? Oder eine schwerwiegende Ausnahme @ 0x352FBB3C32342?
quelle
Wenn der Schaltwert ( Schalter (Variable )) den Standardfall nicht erreichen kann, wird der Standardfall überhaupt nicht benötigt. Selbst wenn wir den Standardfall beibehalten, wird er überhaupt nicht ausgeführt. Es ist toter Code.
quelle
Es ist eine optionale Codierungskonvention. Abhängig von der Verwendung ist, ob es benötigt wird oder nicht. Ich persönlich glaube, wenn Sie es nicht brauchen, sollte es nicht da sein. Warum etwas hinzufügen, das vom Benutzer nicht verwendet oder erreicht wird?
Wenn die Fallmöglichkeiten begrenzt sind (dh ein Boolescher Wert), ist die Standardklausel redundant !
quelle
Wenn eine
switch
Anweisung keinen Standardfall enthält , kann das Verhalten unvorhersehbar sein, wenn dieser Fall zu einem bestimmten Zeitpunkt auftritt, der in der Entwicklungsphase nicht vorhersehbar war. Es ist eine gute Praxis, einendefault
Fall aufzunehmen.Eine solche Vorgehensweise kann zu einem Fehler wie NULL-Dereferenzierung , Speicherverlust sowie anderen Arten schwerwiegender Fehler führen .
Zum Beispiel nehmen wir an, dass jede Bedingung einen Zeiger initialisiert. Wenn jedoch ein
default
Fall auftreten soll und wir in diesem Fall nicht initialisieren, besteht jede Möglichkeit, mit einer Nullzeigerausnahme zu landen. Daher wird empfohlen, einedefault
case-Anweisung zu verwenden, auch wenn diese möglicherweise trivial ist.quelle
Der Standardfall ist in dem von enum verwendeten Switch möglicherweise nicht erforderlich. Wenn der Schalter alle Werte enthielt, wird der Standardfall niemals ausgeführt. In diesem Fall ist dies also nicht erforderlich.
quelle
Hängt davon ab, wie der Switch in einer bestimmten Sprache funktioniert. In den meisten Sprachen wird die Ausführung jedoch ohne Warnung durch die switch-Anweisung geleitet, wenn kein Fall übereinstimmt. Stellen Sie sich vor, Sie haben eine Reihe von Werten erwartet und diese im Schalter behandelt, erhalten jedoch einen anderen Wert in der Eingabe. Nichts passiert und Sie wissen nicht, dass nichts passiert ist. Wenn Sie den Fall in Verzug geraten, wissen Sie, dass etwas nicht stimmt.
quelle
Ich bin mit der oben am häufigsten gewählten Antwort von Vanwaril nicht einverstanden.
Jeder Code erhöht die Komplexität. Auch Tests und Dokumentationen müssen dafür durchgeführt werden. Es ist also immer gut, wenn Sie mit weniger Code programmieren können. Meiner Meinung nach verwende ich eine Standardklausel für nicht erschöpfende switch-Anweisungen, während ich keine Standardklausel für erschöpfende switch-Anweisungen verwende. Um sicherzugehen, dass ich das richtig gemacht habe, verwende ich ein statisches Code-Analyse-Tool. Gehen wir also auf die Details ein:
Nicht erschöpfende switch-Anweisungen: Diese sollten immer einen Standardwert haben. Wie der Name schon sagt, handelt es sich um Aussagen, die nicht alle möglichen Werte abdecken. Dies ist möglicherweise auch nicht möglich, z. B. eine switch-Anweisung für einen ganzzahligen Wert oder für einen String. Hier möchte ich das Beispiel von Vanwaril verwenden (Es sollte erwähnt werden, dass er dieses Beispiel verwendet hat, um einen falschen Vorschlag zu machen. Ich verwende es hier, um das Gegenteil zu sagen -> Verwenden Sie eine Standardanweisung):
Der Spieler kann jede andere Taste drücken. Dann konnten wir nichts tun (dies kann im Code nur durch Hinzufügen eines Kommentars zum Standardfall angezeigt werden) oder es sollte zum Beispiel etwas auf dem Bildschirm gedruckt werden. Dieser Fall ist möglicherweise relevant.
Vollständige switch-Anweisungen: Diese switch-Anweisungen decken alle möglichen Werte ab, z. B. eine switch-Anweisung für eine Aufzählung von Gradsystemtypen. Bei der ersten Codeentwicklung ist es einfach, alle Werte abzudecken. Da wir Menschen sind, besteht jedoch eine geringe Chance, einige zu vergessen. Wenn Sie später einen Aufzählungswert hinzufügen, sodass alle switch-Anweisungen angepasst werden müssen, um sie wieder vollständig zu machen, wird der Pfad zur Fehlerhölle geöffnet. Die einfache Lösung ist ein statisches Code-Analyse-Tool. Das Tool sollte alle switch-Anweisungen überprüfen und prüfen, ob sie vollständig sind oder einen Standardwert haben. Hier ein Beispiel für eine vollständige switch-Anweisung. Zuerst brauchen wir eine Aufzählung:
Dann brauchen wir eine Variable dieser Aufzählung wie
GradeSystemType type = ...
. Eine vollständige switch-Anweisung würde dann folgendermaßen aussehen:Wenn wir also
GradeSystemType
beispielsweise um erweitern, sollteSystem1To3
das statische Code-Analyse-Tool erkennen, dass es keine Standardklausel gibt und die switch-Anweisung nicht vollständig ist, sodass wir sicher sind.Nur eine zusätzliche Sache. Wenn wir immer eine
default
Klausel verwenden, kann es vorkommen, dass das statische Code-Analyse-Tool keine erschöpfenden oder nicht erschöpfenden switch-Anweisungen erkennen kann, da es diedefault
Klausel immer erkennt . Dies ist sehr schlecht, da wir nicht informiert werden, wenn wir die Aufzählung um einen anderen Wert erweitern und vergessen, sie einer switch-Anweisung hinzuzufügen.quelle
Sollten switch-Anweisungen immer eine Standardklausel enthalten? Ohne Standardfall können keine Switch-Fälle existieren. Im Switch-Fall löst der Standardfall
switch(x)
in diesem Fall den Switch-Wert x aus, wenn er nicht mit anderen Fallwerten übereinstimmt.quelle
Ich glaube, das ist ziemlich sprachspezifisch und für den C ++ - Fall ein kleiner Punkt für Enum-Klasse . Welches scheint sicherer als traditionelle C enum. ABER
Wenn Sie sich die Implementierung von std :: byte ansehen, ist es ungefähr so:
Quelle: https://en.cppreference.com/w/cpp/language/enum
Und bedenken Sie auch Folgendes:
Quelle: https://en.cppreference.com/w/cpp/language/list_initialization
Dies ist ein Beispiel für eine Enum-Klasse, die Werte darstellt, die nicht als Enumerator definiert sind. Aus diesem Grund können Sie Enums nicht vollständig vertrauen. Je nach Anwendung kann dies wichtig sein.
Ich mag jedoch sehr, was @Harlan Kassler in seinem Beitrag gesagt hat, und werde diese Strategie in einigen Situationen selbst anwenden.
Nur ein Beispiel für eine unsichere Enum-Klasse:
quelle