Kotlin Language

Controllo di flusso

Le istruzioni relativo al controllo di flusso non differiscono particolarmente, tanto meno come logica, rispetto ad altri linguaggi. Nella tabella che trovate di seguito trovate le sitruzioni delle quali ci occupiamo, se volete potete saltare direttamente a quella che vi interessa.

if
when
for
while
do while
break - continue


Andiamo via veloci, iniziando con il classico if. La sintassi è semplice:

IF

formato 1
if (espressione booleana)
{
  codice
}

formato 2
if (espressione booleana)
{
  codice
}
else
{
  codice
}

formato 3
if (espressione booleana 1)
{
  codice
}
else if (espressione booleana 2)
{
  codice
}
else if (espressione booleana 3)
{
  codice
}
..... altri eventuali branch che iniziano con else if (espressione booleana n-esima)
else
{
  codice
}

Con "espressione booleana" si intende un'istruzione che restituisce un valore booleano, cioè vero o falso. Ad esempio (3 == 9) è falso ( 3 == 3) è vero. Le parentesi graffe possono essere omesse se il codice è costituito da una sola istruzione. Forse è preferibile usarle sempre ma è una questione per lo più di gusti. nei miei esempi, qui e altrove, alternerò i due tipi di scrittura. Nel caso 3, evidentemente, come anche nel 2, l'ultimo else fa da "rastrello" che raccoglie tutti i casi non previsti in precedenza.

  Esempio 5.1
1
2
3
4
5
6
7
8
9
10
11
12
13
fun main(args : Array<String>)
{
  println("Inserisci un numero!")
  var x1 = Integer.parseInt(readLine())
  if ( x1 % 2 == 0)
  {

    println("Numero pari")
  }
  else
  {
    println("Numero dispari")
  }
}

Un uso alternativo del nostro if è di tipo più "funzionale" e ci permette di usare il valore in uscita della espressione come valore di una variabile. L'esempio chiarirà meglio la cosa:

  Esempio 5.2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
fun main(args: Array<String>): Unit
{
  print("Inserisci un valore: ")
  val x1 = Integer.parseInt(readLine())
  print("Inserisci un valore: ")
  val x2 = Integer.parseInt(readLine())
  val max: Int
  max = if (x1 > x2)
  x1
  else if (x1 < x2)
  x2
  else x2
  println("Valore massimo = " + max.toString())
}

Come si vede, al'assegnazione del valore a max avviene alla riga 8 ed è collegato a quanto esce dall'analisi svolta con if. Volendo si può ricorrere ad una sintassi più compatta:

max = if (x1 < x2) x1 else x2

Ovviamente, nel caso di espressioni con più ramificazioni, la prima che viene eseguita, ovvero la cui condizione viene soddisfatta, esclude l'esecuzioni delle altre.

WHEN

Istruzione simile come logica ma più adatta qualora vi fossero numerose selezioni da effettuare su un valore, è when. La sua sintassi è semplice, anche in questo caso ma l'istruzione è assai potente:

when(variabile)
{
  valore 1 -> codice
  valore 2 -> codice
  else -> codice
}


  Esempio 5.3
1
2
3
4
5
6
7
8
9
10
11
12
fun main(args: Array<String>): Unit
{
  print("Inserisci un valore: ")
  val x1 = Integer.parseInt(readLine())
  when(x1)
  {
    0 -> println("Inserito il valore 0")
    1 -> println("Inserito il valore 1")
    2 -> println("Inserito il valore 2")
    else -> println("Inserito valore diverso da 0, 1 o 2")
  }
}

Anche in questo caso l'ultimo else raccoglie tutto quanto non compreso nei casi precedenti. Una domanda ricorrente in questi casi è come porre più istruzioni in uno o più branch; si usao semplicemente le graffe:

when(x1)
{
  0 -> {
       println("Inserito il valore 0")
       println("Inserito il valore zero")
       }
  1 -> println("Inserito il valore 1")
  2 -> println("Inserito il valore 2")
  else -> println("Inserito valore diverso da 0, 1 o 2")
}

Possiamo anche comprendere più casi insieme, separando i valori con una virgola:

when(x1)
{
0,1,2,3,4,5,6,7,8,9 ->
println("Inserito valore < 10")
else -> println("Inserito valore in doppia cifra")
}

Se volete, è anche meglio, in casi come questo, utilizzare una scrittura alternativa:

when(x1)
{
in 0..9 ->
println("Inserito valore < 10")
else -> println("Inserito valore in doppia cifra")
}

e possiamo anche usare when in alcuni casi in piena alternativa a if, appena visto, questo si ottiene quando non si propone un argomento a when; in quel caso ogni branch è caratterizzato dalla presenza di una espressione booleana e quindi viene eseguito il branch che sottende la prima espressione che risulta true:

when
{
  (x1 % 2 == 0) -> println("Pari")
  (x1 % 2 != 0) -> println("Dispari")
}

FOR

Molto conosciuto nell'ambito della programmazione è anche l'istruzione for. Si tratta di un iteratore, che permette di eseguire operazioni cicliche sui dati prescelti. La sintassi è:

for (elemento in collezione)
{
  codice
{

Come in precedenza,  anche qui è possibile evitare le parentesi nel caso in cui il codice sia costituito da una sola istruzione

  Esempio 5.4
1
2
3
4
5
6
7
8
9
fun main(args: Array<String>): Unit
{
  print("Inserisci un valore: ")
  val x1 = Integer.parseInt(readLine())
  for (x2 in 1..x1)
  {
    println(x2)
  }
}

se volete cambiare il passo dovrete usare step:

for (x2 in 1..x1 step 2)

terrà il passo due, saltando quindi un elemento ogni due.
Un altro problema spesso ignorato è quello di percorrere il ciclo all'inverso, ovvero dall'elemento a più alto valore a quello più basso. Non funziona scrivere

for (x in 100..1)

il ciclo non partirebbe neanche, la scrittura giusta è:

for (x in 100 downTo 1)

anche in questo caso si può aggiungere uno step.

Incontreremo il for in molti casi ed esempi.

WHILE

Anche questo ciclo non propone difficoltà concettuali, richiede solo un po' di attenzione. Sintatticamente abbiamo:

while(espressione booleana)
{
  codice
}

Vediamo l'esempio base:

  Esempio 5.5
1
2
3
4
5
6
7
8
9
10
11
fun main(args: Array<String>): Unit
{
  print("Inserisci un valore: ")
  val x1 = Integer.parseInt(readLine())
  var x2 = 0
  while (x2 < x1)
  {
    println(x2)
    x2++
  }
}

ovviamente x2 deve essere dichiarata var, altrimenti non è possibile incrementarla. Un po' di attenzione riguarda la salvaguardia della condizione di uscita che deve potersi verificare altrimenti sia ha un loop infinito. Se volete realizzarlo in maniera più formale, il loop infinito, potete scrivere while(true).
Se la condizione di entrata, nel nostro esempio alla riga 6, non è realizzata, il corpo del while non veien mai eseguito. Per garantire almeno una esecuzione si può ricorrere al prossimo ciclo.

DO WHILE

Usando questo costrutto la condizione viene verificata dopo la prima esecuzione. In fatti la sintassi è:

do
{
  codice
}
while (espressione booleana)

  Esempio 5.6
1
2
3
4
5
6
7
8
9
10
11
12
fun main(args: Array<String>)
{
  print("Inserisci un valore: ")
  val x1 = Integer.parseInt(readLine())
  var x2 = 0
  do
  {
    println(x2)
    x2++
  }
  while(x2 < x1)
}

come si vede l'esecuzione avviene, qualunque sia la condizione almeno, una volta. Valgono le considerazioni espresse per il ciclo while.

BREAK - CONTINUE

Non si tratta, come indicato dalle parole in se stesse, di cili ma sono due istruzioni che possono influenzare l'esecuzione degli stessi. In particolare:

break - interrompre l'esecuzione di un  ciclo
continue - salta per così dire un giro e fa continuare l'esecuzione da quello successivo.

Vediamo con un esempio "in parallelo" come funzionano queste due istruzioni, subito sotto trovate i rispettivi output:

  Esempio 5.7a   Esempio 5.7b
1
2
3
4
5
6
7
8
9
10
11
fun main(args: Array<String>)
{
  val x1 = 9
  var x2 = 0
  while (x2 < x1)
 {
    x2++
    if (x2 == 5) break

    print(x2)
  }
}
1
2
3
4
5
6
7
8
9
10
11
fun main(args: Array<String>)
{
  val x1 = 9
  var x2 = 0
  while (x2 < x1)
  {
    x2++
    if (x2 == 5) continue
    print(x2)
  }
}

01234 012346789

La differenza è evidente, break interrompe l'esecuzione e ripassa il controllo al livello superiore (quindi il programma termina, in questo caso) continue provoca il salto della stampa del numero 5 che, come si può vedere, manca della seconda sequenza.