Poiché if/else
è simile a switch
e spesso intercambiabile, la tua confusione è comprensibile.
Alcune lingue, come Python, non hanno nemmeno un'istruzione switch
. Non sorprendentemente, quando si utilizza Google per "python switch", il primo risultato punta a un'alternativa: una mappa. Non un if/else
, ma una mappa.
Mentre puoi usare if/else
ogni volta invece che switch
, dovresti anche capire che i tuoi colleghi non sono sbagliati quando usano switch
dichiarazione. O è stato semplicemente detto da un insegnante o da un mentore che dovrebbero usare switch
quando ci sono più di due rami, o semplicemente lo trovano più elegante o leggibile , entrambi i termini sono perfettamente soggettivi.
Il tuo primo esempio, a proposito, mi infastidisce molto. Se fossi un recensore del tuo codice, lo segnalerei immediatamente, perché è facile ignorare la mancanza di dichiarazioni break
, quindi sembra come se oldVersion
è 2
, solo updateToVersion3()
verrà eseguito, ma non updateToVersion4()
. Evita di scrivere codice soggetto a errori. Ad esempio, tale sintassi è proibita in C # proprio per evitare errori che sono così facilmente evitabili.
Il tuo secondo esempio è un caso in cui switch
va perfettamente bene . Anche se utilizzerei invece una mappa (funzioni di mappatura, o anche espressioni lambda, e non i loro risultati) o ereditarietà, passerei alla dichiarazione switch
se so che il mio codice verrà letto dai principianti che potrebbero non capire quei due approcci.
Se le linee guida di stile del tuo codice base lo consentono, il tuo secondo esempio potrebbe anche essere scritto in questo modo:
switch (button){
case LEFT: moveLeft(); break;
case RIGHT: moveRight(); break;
case UP: moveUp(); break;
case DOWN: moveDown(); break;
}
o così:
switch (button){
case LEFT: moveLeft(); break;
case RIGHT: moveRight(); break;
case UP: moveUp(); break;
case DOWN: moveDown(); break;
}
rendendo il codice più breve e più leggibile (anche in questo caso, la leggibilità è soggettiva) rispetto a una variante if/elif/else
.
Un aspetto importante evidenziato di J Trana è che in questo secondo esempio, if/elif/else
potrebbe essere soggetto a errori. Non riesco a trovare facilmente un esempio più esplicativo in cui è possibile migrare a switch
, ma la seguente parte di codice mostra l'idea. Sei in grado di capire immediatamente perché il codice seguente a volte genera un'eccezione in fase di esecuzione (immagina che siano le sei del pomeriggio e hai passato tre ore a ispezionare il codice)?
if (!fs.FileExists(fileFullPath)) {
debug("The file appears to be missing. Check if the location is set in the options.");
}
if (fs.ReadFile(fileFullPath).Contains(textToFind)) {
found = true;
debug("The file contains the expected text.");
}
else {
debug("The text was not found.");
}
Anche in questo caso, in C #, la guida di stile ufficiale ti impedirà di scrivere questa parte di codice soggetta a errori: sarà necessario aggiungere un'interruzione di riga prima del secondo if
, e l'autore del codice vedrà immediatamente che ha scritto if
invece di else if
.
Ecco perché, per ridurre il rischio di scrivere codice che non esprime chiaramente le intenzioni dell'autore e può essere facilmente letto male:
-
Evita le break
s mancanti nelle istruzioni switch
, tranne nel caso in cui il precedente case
non contenga alcuna logica:
switch (something)
{
case 1: // Not having a 'break' is fine. The intention of the author is clear.
case 2:
hello();
break;
case 3:
world();
break;
}
-
Evita else if
che può essere confuso con o, per errore, sostituito da, un if
, a meno che le linee guida sullo stile non ti proteggano.
-
Usa mappe ed ereditarietà quando appropriato. In la maggior parte dei casi, le mappe e l'ereditarietà sono più appropriate di if/elif/else
o switch
. Il più lungo if/elif/else
o switch
tendono ad essere un buon segno che dovrebbero essere sostituiti da una mappa (spesso) o un'ereditarietà (raramente) o dovrebbero essere completamente refactored (spesso).
Il record che ho visto finora è una dichiarazione switch
contenente circa il mille% dicase
s (scritta da un esperto orgoglioso della sua esperienza professionale di 15 anni come sviluppatore principale ).
-
Appiattisci le gerarchie quando possibile. Questo codice:
if (n == a) {
f1();
}
else {
if (n == b) {
f2();
}
else {
f3();
}
}
dovrebbe essere immediatamente refactored in:
if (n == a) {
f1();
}
else if (n == b) {
f2();
}
else {
f3();
}
o
switch (n) {
case a: f1(); break;
case a: f2(); break;
default: f3();
}
-
Attenzione ai programmatori folle. Questo pezzo di codice è equivalente a quello del punto precedente, se a
, b
, c
e n
sono numeri (le cose sarebbero diverse se si trattasse di chiamate a funzioni con effetti collaterali):
if (!(n == a)) {
if (n - b == 0 && !(n > b)) {
f2();
}
}
if (!(n == a) && n - b < 0 || b - n < 0) {
f3();
}
if (n != a) {
// Do nothing.
}
else {
if (!(n > a) && ! (n < a)) {
f1();
}
}