it-swarm.it

Dovrei usare le istruzioni switch o lunghe se ... altrimenti catene?

Spesso quando sento parlare dell'istruzione switch, viene rimandato come un modo per sostituire lunghe catene se ... altro. Ma sembra che quando uso l'istruzione switch sto scrivendo più codice che scriverei solo se ... altro. Hai anche altri problemi come mantenendo tutte le variabili per tutte le chiamate nello stesso ambito .

Ecco del codice che rappresenta il flusso che scrivo normalmente ( grazie a diam )

String comment;   // The generated insult.
int which = (int)(Math.random() * 3);  //  Result is 0, 1, or 2.

if (which == 0) {
    comment = "You look so much better than usual.";
} else if (which == 1) {
    comment = "Your work is up to its usual standards.";
} else if (which == 2) {
    comment = "You're quite competent for so little experience.";
} else {
    comment = "Oops -- something is wrong with this code.";
}

Quindi vogliono che lo sostituisca con questo:

String comment;   // The generated insult.
int which = (int)(Math.random() * 3);  //  Result is 0, 1, or 2.

switch (which) {
    case 0:  
             comment = "You look so much better than usual.";
    break;
    case 1:  
             comment = "Your work is up to its usual standards.";
    break;
    case 2:  
             comment = "You're quite competent for so little experience.";
    break;
    default: 
             comment = "Oops -- something is wrong with this code.";
}

Sembra molto più codice in una sintassi molto più imbarazzante. Ma c'è davvero un vantaggio nell'usare l'istruzione switch?

36
TheLQ

Per questa particolare situazione, mi sembra che sia if che case siano scelte sbagliate. Userei un array semplice:

String comments[] = {
    "You look so much better than usual.",
    "Your work is up to its usual standards.",
    "You're quite competent for so little experience."
};

String comment = comments[(int)(Math.random() * 3)];

Come nota a margine, dovresti generalmente calcolare il moltiplicatore in base alla dimensione dell'array piuttosto che codificare 3.

Quanto a quando vorresti usi un case/switch, la differenza da una cascata di istruzioni if (o almeno una differenza maggiore) è che switch può semi- ottimizza automaticamente in base al numero e alla densità dei valori, mentre una cascata di istruzioni if lascia il compilatore con poca scelta ma per generare il codice mentre lo hai scritto, testando un valore dopo l'altro fino a trovare una corrispondenza. Con solo tre casi reali, non è certo un problema, ma con un numero sufficiente può/potrebbe essere significativo.

57
Jerry Coffin

Il problema con il if...else if... chain è che quando arrivo per leggerlo, devo guardare ogni singola condizione if per capire cosa sta facendo il programma. Ad esempio, potresti avere qualcosa del genere:

if (a == 1) {
    // stuff
} else if (a == 2) {
    // stuff
} else if (a == 3) {
    // stuff
} else if (b == 1) {
    // stuff
} else if (b == 2) {
    // stuff
}

(ovviamente, per un piccolo numero di affermazioni come questa, non è poi così male)

Non avrei modo di sapere che hai modificato la variabile di condizione a metà strada senza leggere ogni singola istruzione. Tuttavia, poiché un switch ti limita a una singola variabile di condizione, posso vedere a colpo d'occhio cosa sta succedendo.

Alla fine, però, preferirei né switch né una catena di if...else if. Spesso una soluzione migliore è una sorta di tabella di salto o dizionario per casi come nella domanda originale o polimorfismo (se la tua lingua lo supporta). Ovviamente non è sempre possibile, ma cercherò una soluzione che eviti switch come primo passo ...

23
Dean Harding
switch (which) {
  case 0: comment = "String 1"; break;
  case 1: comment = "String 2"; break;
  case 2: comment = "String 3"; break;
  default: comment = "Oops"; break;
}

Il modo sopra descritto per scrivere questo tipo di custodia è abbastanza comune. Il motivo per cui hai sentito il caso switch se più voluminoso è perché il tuo corpo era solo una linea e con un caso switch hai anche bisogno dell'istruzione break. Quindi la custodia dell'interruttore aveva il doppio della dimensione del corpo di if else. Con un codice più sostanziale, l'istruzione break non aggiungerà molto al corpo. Per il corpo a riga singola, è pratica comune scrivere il codice nella stessa riga dell'istruzione case.

Come altri hanno già accennato, un caso switch rende più chiaro l'intento, vuoi prendere una decisione in base al valore di una singola variabile/espressione. I miei commenti sono puramente dal punto di vista della leggibilità e non basati sulle prestazioni.

14
aufather

In questo caso, l'istruzione switch corrisponde più chiaramente all'intento del codice: scegli un'azione da eseguire in base a un singolo valore.

Le dichiarazioni if ​​d'altra parte sono molto più difficili da leggere - devi guardarle tutte per essere sicuro di cosa sta succedendo. Per me è meno codice (anche se il conteggio dei caratteri può è leggermente più alto) in quanto c'è meno da analizzare mentalmente.

8
FinnNk

Concordo con Jerry sul fatto che una serie di stringhe è migliore per questo caso particolare, ma che in generale è meglio usare un'istruzione switch/case piuttosto che una catena di elseif. È più facile da leggere e a volte il compilatore può fare un lavoro migliore per l'ottimizzazione in questo modo, ma c'è anche un altro vantaggio: è molto più facile eseguire il debug.

Quando premi questo interruttore, devi solo fare un passo una volta per finire sul ramo giusto, invece di scavalcare attentamente diverse istruzioni if ​​una alla volta, e possibilmente premere la chiave troppo velocemente e superarla e perdere qualcosa e avere ricominciare da capo.

8
Mason Wheeler

Preferisco passare a questo tipo di casi, corrisponde molto meglio al punto del codice, esegue un'istruzione diversa per ogni diverso valore di input. Il if..else agisce più come un "trucco" per ottenere lo stesso effetto.

switch sono anche più pulite, è facile avere un refuso nascosto in tutte quelle ==

Inoltre, per blocchi di grandi dimensioni in C, l'interruttore è più veloce.

else..if può essere più appropriato quando hai qualcosa come intervalli (tra 1 e 100, fai questo, tra 100 e 200 fai quello), o in C, quando provi a cambiare con elementi come stringhe (che è possibile in altre lingue ). Che è lo stesso.

Tendo a usare molti switch quando programmo in C.

3
Khelben

In genere non mi piace nessuno dei due approcci. Passaggio lungo o se le istruzioni semplicemente implorano di essere refactored ad un'astrazione orientata agli oggetti (comunque il tuo esempio lo classificherei come breve, non lungo).

Avrei personalmente avvolto quel tipo di codice in un metodo di supporto separato.

private string GetInsult()
{
    int which = (int)(Math.random() * 3);  //  Result is 0, 1, or 2.

    switch (which) {
        case 0: return "You look so much better than usual.";
        case 1: return "Your work is up to its usual standards.";
        case 2: return "You're quite competent for so little experience.";
        default: return "Oops -- something is wrong with this code.";
    }
}

public void Foo()
{
    string comment = GetInsult();
    Print(comment);
}

Posizionare lo switch in un metodo separato consente di posizionare le istruzioni return direttamente all'interno dell'istruzione switch (almeno in c #), eliminando la necessità di istruzioni break, rendendo il codice molto più facile da leggere.

E questo è molto più bello dell'approccio if/else if/else if.

2
Pete

Scegli qualcosa che sia efficiente, conciso e quindi documento non solo quello che hai fatto, ma perché.

Il codice può essere rivisitato e non sempre dal suo autore originale.

Ci sono momenti in cui puoi scegliere deliberatamente un'implementazione piuttosto che un'altra perché stai pensando al codice che non esiste.

2

Una delle cose che rende particolarmente fastidioso lo stile C/C # switch è l'insistenza sul fatto che il valore case sia letterale. Una cosa bella di VB/VB.NET è che select/case consente a ogni caso di essere qualsiasi espressione booleana. Quello è conveniente. Nella misura in cui una serie di espressioni booleane reciprocamente esclusive è spesso utile, una serie di if/else ifs è più flessibile, per non parlare della maggiore efficienza nella digitazione e nella lettura.

0
Joel Brown

In Python non esiste alcuna istruzione switch, perché se/Elif/else è Nice:

a = 5

if a==1:
    print "do this"
Elif a == 2:
    print "do that"
Elif a == 3:
    print "do the other"
Elif 3 < a < 9:
    print "do more"
Elif 9 <= a < 15:
    print "do nothing"
else:
    print "say sorry"

Semplice vero?

0