Lezione 2 di 7 · 16 min di lettura
switch, il bivio a più strade
Un valore, tante strade possibili. Il break automatico, i casi raggruppati, gli intervalli, le stringhe e nextcase.
Quando gli else if non finiscono più
Immagina di dover stampare il nome del giorno a partire dal suo numero. Con if verrebbe una catena di sette else if, tutti uguali: if (day == 1) ... else if (day == 2) .... Funziona, ma è ripetitivo, e stai confrontando sempre la stessa variabile con valori diversi.
Per questo caso esiste switch:
import std::io;
fn void main()
{
int day = 3;
switch (day)
{
case 1:
io::printn("Monday");
case 2:
io::printn("Tuesday");
case 3:
io::printn("Wednesday");
default:
io::printn("Another day");
}
}Wednesdayswitch (day) dice “guarda il valore di day”. Ogni case è una possibile strada: il programma salta direttamente a quella col valore giusto ed esegue le istruzioni che seguono. default è la strada di riserva, presa quando nessun case corrisponde (è facoltativo, come l’else).
Nota una cosa: dopo Wednesday il programma non ha stampato anche Another day. Ogni case finisce da solo, dove comincia il successivo.
Più valori, stessa strada
A volte più valori vanno trattati allo stesso modo. Basta mettere i case uno sotto l’altro, lasciando vuoti quelli sopra:
int day = 7;
switch (day)
{
case 6:
case 7:
io::printn("Weekend!");
default:
io::printn("Work day");
}Weekend!Un case completamente vuoto prosegue nel successivo: case 6: non ha istruzioni, quindi 6 finisce nello stesso blocco di 7. È l’unica eccezione alla regola del “finisce da solo”, e ha senso: un case vuoto non avrebbe altro da fare.
(Se vieni da altri linguaggi potresti provare case 6, 7: con la virgola: in C3 non esiste, e il compilatore risponde Missing ':' after case.)
Intervalli: case 13..17
Quando i valori sono tanti e consecutivi, elencarli uno a uno sarebbe assurdo. C3 permette gli intervalli, con due punti tra gli estremi:
int age = 17;
switch (age)
{
case 0..12:
io::printn("Child");
case 13..17:
io::printn("Teenager");
default:
io::printn("Adult");
}TeenagerGli estremi sono inclusi: 0..12 comprende sia 0 che 12. E se due case si sovrappongono o si ripetono, il compilatore se ne accorge: The same case value appears more than once.
Non solo numeri: switch sulle stringhe
Un switch funziona anche con le String, e diventa perfetto per interpretare dei comandi:
String command = "save";
switch (command)
{
case "open":
io::printn("Opening...");
case "save":
io::printn("Saving...");
case "quit":
io::printn("Bye!");
default:
io::printfn("Unknown command: %s", command);
}Saving...E naturalmente funziona con i char: case '+':, case 'q': e così via. Lo userai nell’esercizio.
Quiz
Cosa stampa questo codice con int n = 2;? switch (n) { case 1: io::printn("one"); case 2: io::printn("two"); case 3: io::printn("three"); }
nextcase: proseguire di proposito
E se invece vuoi proprio che un caso prosegua nel successivo? Lo dici esplicitamente con nextcase. Un esempio: in un videogioco, raggiungere un livello sblocca anche tutti i luoghi dei livelli precedenti.
int level = 2;
switch (level)
{
case 3:
io::printn("Unlocked: dragon");
nextcase;
case 2:
io::printn("Unlocked: castle");
nextcase;
case 1:
io::printn("Unlocked: village");
}Unlocked: castle
Unlocked: villageSi entra in case 2, si stampa il castello, e nextcase fa proseguire in case 1. Chi legge vede subito che è voluto. nextcase può anche saltare a un caso preciso, per esempio nextcase 1;, ma è raro averne bisogno.
switch senza niente tra parentesi
Ultima variante, sorprendentemente comoda: uno switch senza espressione. Ogni case contiene allora una condizione, e vince la prima vera, come in una catena di else if:
double bmi = 22.4;
switch
{
case bmi < 18.5:
io::printn("Underweight");
case bmi < 25.0:
io::printn("Normal");
default:
io::printn("Overweight");
}NormalÈ una questione di gusto: alcuni la trovano più ordinata di una fila di else if, soprattutto quando le condizioni sono tante.
Dettagli nerd Perché uno switch può essere più veloce di tanti if?
Una catena di if fa i confronti uno dopo l’altro: con 50 casi, per arrivare all’ultimo servono 50 confronti. Quando i case sono numeri vicini tra loro, invece, il compilatore può costruire una tabella dei salti (jump table): un elenco in memoria con l’indirizzo del codice di ogni caso. Il valore di day diventa direttamente la posizione nella tabella: un calcolo, un salto, fatto. Che i casi siano 5 o 500, il tempo è lo stesso.
Non devi fare niente per ottenerlo: il compilatore sceglie da solo la strategia migliore. Ma è un bel motivo per preferire switch quando confronti un valore con tante costanti.
Esercizio · sul tuo computer
Calcolatrice e pagella
Scrivi calculator.c3 con queste variabili:
int a = 12;
int b = 4;
char op = '*';
int score = 83;- Con uno
switchsuop, gestisci i quattro operatori'+','-','*','/': per ognuno stampa l’operazione e il risultato nel formato12 * 4 = 48. NeldefaultstampaUnknown operator:seguito dal carattere. - Con un secondo
switchsuscore, usando gli intervalli, stampaGrade: Aper 90–100,Grade: Bper 80–89,Grade: Cper 70–79,Grade: Dper 60–69, eGrade: Fper tutto il resto.
Riporta l’output. Poi prova op = '/', op = '%' e altri voti.
Mostra una soluzione (prima prova da solo!)
import std::io;
fn void main()
{
int a = 12;
int b = 4;
char op = '*';
int score = 83;
switch (op)
{
case '+':
io::printfn("%d + %d = %d", a, b, a + b);
case '-':
io::printfn("%d - %d = %d", a, b, a - b);
case '*':
io::printfn("%d * %d = %d", a, b, a * b);
case '/':
io::printfn("%d / %d = %d", a, b, a / b);
default:
io::printfn("Unknown operator: %c", op);
}
switch (score)
{
case 90..100:
io::printn("Grade: A");
case 80..89:
io::printn("Grade: B");
case 70..79:
io::printn("Grade: C");
case 60..69:
io::printn("Grade: D");
default:
io::printn("Grade: F");
}
}Ricapitolando
switch (valore)salta alcasecorrispondente;defaultraccoglie il resto.- Ogni
caseesce da solo alla fine: nientebreakda dimenticare. - I
casevuoti proseguono nel successivo: così si raggruppano più valori. case 13..17:copre un intervallo, estremi inclusi.- Si può fare
switchsu interi,chareString; senza espressione, ognicaseè una condizione. nextcasefa proseguire di proposito nel caso successivo.
Ora il programma sa scegliere. Prossimo superpotere: ripetere. Cominciamo con il ciclo più semplice, while.