Capitolo 4

Condizioni: far scegliere al programma

Fino ad ora i programmi eseguivano tutte le istruzioni in ordine. Adesso impari a decidere: eseguire un pezzo di codice solo se una condizione è vera. Si impara in due modi: if (se) e when (quando).

In questo capitolo impari

Ripasso lampo: leggere i dati e convertirli

Prima di decidere, il programma deve avere i dati: ripasso del capitolo 3.

L'utente scrive 12. Che cosa stampa questo programma?

fun main() {
    val n = readln()
    println(n + 1)
}
13No: n è testo, quindi n + 1 attacca i due pezzi invece di sommarli.
121Esatto: manca toInt(). Con readln().toInt() il risultato sarebbe 13.
Un erroreKotlin non dà errore: trasforma l'1 in testo e unisce tutto in una stringa.

readln() restituisce sempre testo: senza .toInt() il + unisce invece di sommare. È l'errore più frequente di tutto il manuale.

L'utente scrive ciao. Che cosa stampa questo programma?

fun main() {
    val n = readln().toIntOrNull() ?: 0
    println(n * 2)
}
0Esatto: toIntOrNull()null, e ?: mette 0 al suo posto. 0 * 2 è 0.
Un errore di conversioneQuesto succederebbe con toInt(); con toIntOrNull() il programma continua.
ciaociaoNo: ?: scarta il testo non convertibile e usa il valore di riserva.

toIntOrNull() non fa mai fermare il programma: quando la conversione non riesce restituisce null, e il valore di riserva lo scegli tu con ?:.

4.1 if: eseguire solo se...

La forma base è if (condizione) { ... }: le istruzioni fra graffe vengono eseguite solo se la condizione è vera. Con else si indica che cosa fare quando è falsa.

Le graffe si possono evitare, ma...

Se il ramo contiene una sola istruzione puoi scrivere if (eta >= 18) println("Maggiorenne"). Per cominciare usa sempre le graffe: il codice resta chiaro e non fai errori quando aggiungi istruzioni.

4.2 Confronti e operatori logici

Una condizione è un'espressione che vale true o false. Si costruisce con gli operatori di confronto e si combina con quelli logici.

OperatoreSignificatoEsempio
==uguale a (due segni di uguale!)voto == 10
!=diverso danome != "Anna"
> >=maggiore, maggiore o ugualeeta >= 18
< <=minore, minore o ugualeprezzo < 10
&&e: vero solo se lo sono entrambeeta >= 14 && eta < 18
||o: vera se lo è almeno unagiorno == "sab" || giorno == "dom"
!non: rovescia vero e falso!haLaSpada

Che cosa stampa questo programma?

fun main() {
    val voto = 9
    if (voto >= 6) println("sufficiente")
    else if (voto >= 9) println("ottimo")
    else println("insufficiente")
}
ottimoIl voto 9 soddisfa anche 9 >= 6, e quella condizione viene controllata prima.
sufficienteEsatto: Kotlin si ferma alla prima condizione vera, quindi il ramo >= 9 non viene mai raggiunto con questo ordine.
insufficienteNo: la prima condizione è vera, quindi si entra in quel ramo.

Le condizioni vanno scritte dalla più stretta alla più larga. Qui l'ordine giusto è >= 9 prima e >= 6 dopo.

Un solo uguale assegna, due uguali confrontano

if (eta = 18) è un errore: con = si assegna un valore. Per confrontare si usa sempre ==.

4.3 else if: più di due possibilità

Quando le possibilità sono più di due si incatena else if. Kotlin le controlla dall'alto verso il basso e si ferma alla prima condizione vera.

  1. Con voto = 7 la prima condizione (7 >= 9) è falsa, la seconda (7 >= 6) è vera: Kotlin stampa Promosso e non guarda le condizioni successive.
  2. Il secondo if non stampa niente: restituisce il testo "promosso/a", che finisce nella variabile esito.
  3. Da qui le due righe di output: Promosso e Esito: promosso/a.
Perché l'ordine conta

Con voto = 9 la prima condizione è vera e il programma non guarda le altre. Se avessi messo per prima voto >= 6, anche un 10 sarebbe finito in "Sufficiente": si va sempre dal caso più restrittivo a quello più generico.

4.4 if come espressione: assegnare un valore

In Kotlin if può restituire un valore: è il modo più compatto per scegliere fra due valori e metterli in una variabile.

4.5 when: tanti casi in modo ordinato

when confronta un valore con tanti casi. È come una catena di else if, ma molto più leggibile. Il caso else è obbligatorio quando nessuna condizione copre tutti i valori possibili.

Che cosa significa in 0..59

in 0..59 si legge "da 0 a 59, estremi compresi": è il modo per dire al when di scegliere quel ramo quando il valore cade dentro quell'intervallo. Con il voto 78, il primo intervallo (0-59) non lo contiene, il secondo (60-100) sì: stampa Sufficiente. Niente funzioni, return o controlli di tipo: è un when con soggetto e intervalli, che leggerai più in dettaglio nel capitolo 5.

  1. 6 non è nella prima riga di casi, ma è nella seconda: Weekend.
  2. 15 > 10 è vero e 15 % 5 == 0 è vero: con && servono entrambe vere, quindi true.
  3. 15 > 20 è falso e 15 < 0 è falso: con || basta una condizione vera, quindi false.

Che cosa succede con if (eta = 18) { ... }?

Confronta eta con 18No: il confronto si scrive con due uguali.
Kotlin dà un erroreEsatto: = serve ad assegnare un valore. Per confrontare si usa sempre ==.
Assegna 18 a eta e va avantiL'intenzione sarebbe quella, ma dentro la condizione di un if Kotlin non lo accetta: è quasi sempre un errore di scrittura.

Da ricordare: = assegna, == confronta.

when anche come espressione

val premio = when (punti) { ... else -> 0 } funziona come if: il valore del ramo scelto diventa il valore di tutta l'espressione.

Il caso in cui l'else è obbligatorio

Quando un when con soggetto restituisce un valore — cioè il suo risultato finisce in una variabile o dentro una stampa — il caso else non è un consiglio: è un requisito. Il motivo lo dice il messaggio stesso del motore: «il suo valore viene usato, quindi deve esistere un caso per ogni possibilità». Se invece il when è solo una sequenza di istruzioni, come negli esempi 9–11, mancare un caso non dà errore: semplicemente non succede niente. L'abitudine giusta resta una sola: metti sempre l'else.

4.6 Riepilogo

ScriviSignificato
if (c) { ... } else { ... }due strade possibili
if (c) { ... } else if (c2) { ... } else { ... }più strade, in ordine
val x = if (c) a else buna variabile che prende uno dei due valori
when (x) { 1 -> ...; else -> ... }confronto con tanti casi
when { c1 -> ...; c2 -> ...; else -> ... }catena di condizioni

4.7 Esercizi guidati

Leggi un voto da 0 a 10 e stampa: "Insufficiente" se è minore di 6, "Sufficiente" da 6 a 7, "Buono" da 8 a 9, "Eccellente" se è 10. Usa if / else if / else.

Parti dal caso più alto o dal più basso e prosegui in ordine: if (voto >= 10) ... else if (voto >= 8) ....

  1. Le condizioni vanno dal caso più alto al più basso. Con voto = 10 la prima condizione è vera e le altre non vengono nemmeno guardate.
  2. Se l'input non è un numero, ?: -1 assegna -1 e il programma finisce nel ramo else invece di fermarsi con un errore.
  3. Ogni ramo ha un solo println: avresti potuto omettere le graffe, ma così il codice è pronto per aggiungere altre istruzioni.

Leggi un anno e stabilisci se è bisestile. Regola: un anno è bisestile se è divisibile per 4, tranne gli anni divisibili per 100, che sono bisestili solo se divisibili per 400. Prova con 1900 (non bisestile), 2000 (bisestile) e 2024 (bisestile).

Puoi scrivere tutte le condizioni in un unico if con && e ||: anno % 4 == 0 && (anno % 100 != 0 || anno % 400 == 0).

  1. anno % 4 == 0 è la condizione principale: senza quella nessun anno può essere bisestile.
  2. Le parentesi attorno a (anno % 100 != 0 || anno % 400 == 0) sono essenziali: && ha la precedenza su ||, quindi senza parentesi il significato cambierebbe.
  3. 1900 è divisibile per 4 e per 100 ma non per 400 → non bisestile. 2000 è divisibile per 400 → bisestile. 2024 non è divisibile per 100 → bisestile.
  4. Il risultato viene messo in una val con un nome chiaro: il codice che segue si legge come una frase in italiano.

Il distributore automatico ha questo menu: 1 = acqua (0.50), 2 = succo (1.20), 3 = caffè (0.90), 4 = snack (1.50). Leggi il numero scelto e i soldi inseriti, poi stampa cosa è stato scelto e il resto da restituire. Se il numero non è nel menu stampa "Scelta non valida".

Con when assegna il prezzo: val prezzo = when (scelta) { 1 -> 0.50 ... else -> 0.0 }. Il resto è soldi - prezzo: se il prezzo è 0.0 non c'è nulla da comprare.

  1. Un when come espressione restituisce il valore del ramo scelto: il primo lo usiamo per il nome, il secondo per il prezzo.
  2. L'else del when serve sia per il nome sia per il prezzo: se la scelta non è 1-4 il prezzo resta 0.0.
  3. Dopo il when ci sono tre casi distinti gestiti con if / else if / else: prezzo nullo, soldi sufficienti, soldi insufficienti.
  4. soldi >= prezzo confronta due Double: il confronto funziona anche con i decimali.

Questo programma parte senza errori, ma con voto = 9 stampa Sufficiente invece di Ottimo. Eseguilo, confronta l'output con quello atteso e correggi solo l'ordine delle condizioni, senza cambiare i testi stampati.

Kotlin si ferma alla prima condizione vera: il caso più stretto (voto >= 9) deve stare prima di quello più largo (voto >= 6).

  1. Il codice di partenza compila: l'errore è logico, non di sintassi. Con voto = 9 la prima condizione 9 >= 6 è già vera.
  2. Kotlin entra nel primo ramo e non guarda gli altri: il ramo >= 9 diventa irraggiungibile.
  3. Mettendo voto >= 9 per primo, il 9 finisce in "Ottimo", il 7 in "Sufficiente" e il 4 in "Insufficiente".
  4. Regola generale: le condizioni vanno scritte dalla più stretta alla più larga.

Il programma deve dire se un voto è sufficiente, ma non funziona. Con 7 deve stampare Sufficiente, con 5 deve stampare Insufficiente.

Per confrontare serve == (due uguali); le due condizioni di un && stanno dentro le stesse parentesi tonde dell'if.

  1. if (voto = 6) usa un solo =, che assegna: per confrontare si scrive voto >= 6 o voto == 6.
  2. Le graffe non sono obbligatorie con una sola istruzione, ma con if e else su più righe evitano di sbagliare a quale ramo appartiene l'istruzione.
  3. if (voto >= 6) && (voto <= 10) chiude le parentesi troppo presto: la condizione completa va dentro una sola coppia di parentesi, if (voto >= 6 && voto <= 10).
  4. Kotlin controlla tutta la condizione e solo dopo decide: un && fuori posto non è "quasi giusto", è un errore.
  • so scrivere una condizione con if, else if e else
  • so scegliere fra >, <, >=, <=, ==, !=
  • so combinare le condizioni con &&, || e !
  • so usare if come espressione per assegnare un valore
  • so scrivere un when con valori, intervalli e casi else
  • so spiegare perché l'ordine delle condizioni cambia il risultato
  • so leggere un messaggio di errore e correggere il programma da solo