Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
vuoi
o PayPal
tutte le volte che vuoi
Array
di ogni elemento del vettore per ogni dato indice. Alcuni esempi nel listato 13:
val a r r a y = a r r a y O f ( 1 , 2 , 3 , 4 ) // Inferred type : Array < Int >
1 val a r r a y 2 : Array<Long> = a r r a y O f ( 1 , 2 , 3 , 4 )
2
3 // Creates an Array < String > with values ["0" , "3" , "6" , "9" , "12" , "15"]
4 { −> ∗ }
val a r r a y 3 = Array ( 6 , i ( i 3 ) . t o S t r i n g ( ) )
5 Listato 13: Alcuni esempi di creazione di vettori in Kotlin
Stringhe e string templates
Il comportamento delle stringhe in Kotlin è simile a quello visibile in Java, con
alcuni miglioramenti.
Le stringhe in Kotlin si indicano con il tipo di dato e sono, come in
String
Java, immutabili.
É possibile accedere agli elementi delle stringhe tramite l’indexing operator
(per esempio nello stesso modo in cui si accede agli elementi di un vet-
str[i]),
tore, oppure tramite l’iterazione all’interno di un ciclo. La concatenazione di più
stringhe avviene come in Java tramite l’operatore e funziona anche quando è
+
necessario concatenare stringhe e altri tipi di valori.
Nonostante sia presente l’operatore di concatenazione, è spesso preferibile uti-
lizzare i cosiddetti string templates: è possibile posizionare una variabile all’inter-
no di una stringa tramite l’uso del carattere che funge da segnaposto. Durante
$
l’interpolazione, i segnaposto vengono rimpiazzati con i rispettivi valori. Questo
meccanismo rende il codice più ordinato, evitando di dividere la stringa in porzioni
ogniqualvolta occorra inserire il valore di una variabile o di un’espressione.
Nel listato 14 vengono mostrati alcuni esempi:
val s t r = " Hello "
1 val c = s t r [ 1 ] // Inferred type : Char
2 17
18 {
f o r ( i in s t r )
3 // ...
4 }
5
6 val s t r 2 = + 1 + + 2
" alfa " " beta " // str2 = " alfa1beta2 "
7
8 val i = 30
9 p r i n t l n ( )
" i = $i " // Prints " i = 30"
10
11 val s t r 3 = " abcde "
12 p r i n t l n ( )
" $str3 . length is $ { str3 . length } " // Prints " abcde . length is 5"
13 Listato 14: Alcuni esempi di utilizzo delle stringhe e string
templates in Kotlin
3.4 Inferenza di tipo
Come già accennato negli esempi precedenti, in Kotlin quando la dichiarazione e
l’inizializzazione di una variabile avvengono sulla stessa linea di codice, è possibile
omettere l’indicazione del tipo della variabile. Questo meccanismo, non presente
in questi termini in Java, viene chiamato inferenza di tipo: il compilatore inferisce
automaticamente il tipo dal contesto, perciò non è necessario che il programmatore
lo specifichi esplicitamente.
È possibile osservare inferenza in molteplici esempi precedentemente mostrati:
a linee 1 e 2 del listato 4, a linea 8 del listato 5, a linee 1 e 4 del listato 9 ed infine
a linea 1 del listato 10.
Se tuttavia si volesse assegnare un valore intero ad una variabile contenente
una stringa, bisognerebbe specificare un tipo in comune tra e in
String Int:
questo caso si dovrebbe optare per (esempio nel listato 15).
Any
var name : Any = " Sara "
1 name = 15 // Allowed
2 Listato 15: Utilizzo del tipo Any
è l’equivalente del tipo di Java, rappresenta la radice della gerarchia
Any Object
dei tipi di Kotlin, di conseguenza tutte le classi ereditano da esso (pertanto anche
le classi e
String Int). 18 19
Come si può notare dal prossimo listato 16, l’inferenza di tipo non si limita
soltanto ai tipi di dato di base, ma funziona egregiamente anche con funzioni e
tipi composti quali coppie di valori e mappe:
{
fun sum ( a : Int , b : Int ) : Int
1 return a + b
2 }
3
4 // Inferred type : Int
5 val t o t a l = sum ( 3 0 , 4 0 )
6
7 // Inferred type : Pair < Int , String >
8 val p a i r = t o t a l t o " Seventy "
9
10 // Inferred type : Pair < Pair < Int , String > , Float >
11 val m u l t i P a i r = t o t a l t o t o 7 0 . 0 f
" Seventy "
12
13 // Inferred type : Map < Int , String >
14 val map = mapOf ( t o t a l t o , 90 t o )
" Seventy " " Ninety "
15
16 // Inferred type : Map < Int , Any >
17 val superMap = mapOf ( t o t a l t o , 90 t o 9 0 . 0 f )
" Seventy "
18 Listato 16: Applicazioni d’inferenza di tipo in Kotlin
3.5 Strict null safety
Come probabilmente è stato sperimentato nel tempo da molti programmatori Java,
una delle sorgenti d’errore più diffuse è il non corretto controllo dei valori nulli,
con conseguente lancio dell’insidiosa NullPointerException.
Per evitare questo genere di problemi alcuni linguaggi moderni, compreso Ko-
tlin, possiedono un meccanismo di sicurezza dalla nullabilità inserito direttamente
all’interno del proprio type system. In questo modo è possibile scrivere codice
molto più sicuro e convertire gli errori a tempo di esecuzione in errori a tempo di
compilazione; un vantaggio non da poco. Il meccanismo viene chiamato strict null
safety (o più semplicemente null safety) e funziona poiché il type system di Kotlin
distingue tra i riferimenti che possono contenere valori nulli (nullable references)
e quelli che invece non possono (non-nullable references). Di default i tipi non
possono contenere valori nulli e ciò viene reso possibile solamente se esplicitamen-
19
20
te indicato dal programmatore. Un esempio è quello mostrato da riga 1 a 6 del
precedente listato 5.
Operatore di chiamata sicura
L’operatore di chiamata sicura (safe call operator ) si indica con i caratteri e si
?.
comporta nel seguente modo: prima di tutto compie in automatico un controllo
sulla nullabilità della parte a sinistra dell’operatore, se l’esito risulta essere positivo
allora restituisce altrimenti (valore non nullo) esegue e restituisce il risultato
null,
dell’espressione sulla parte destra.
La sintassi di questo operatore è la seguente:
object?.method
Nei seguenti listati 17 e 18 vengono mostrati due esempi a confronto (il primo in
codice Java, il secondo in Kotlin) su Android:
@Override JAVA
1 {
public v o i d o n C r e a t e ( Bundle s a v e d I n s t a n c e S t a t e )
2 super . o n C r e a t e ( s a v e d I n s t a n c e S t a t e ) ;
3 // Correct compilation but possible error at runtime !
4 f i n a l b o o l e a n i s S w i t c h e d O n = s a v e d I n s t a n c e S t a t e . g e t B o o l e a n ( ) ;
" switch "
5 }
6 Listato 17: Possibile errore a tempo di esecuzione in Java
Sebbene il codice Java compili correttamente, la chiamata al metodo getBoolean
sull’oggetto può provocare un errore a tempo di esecuzione,
savedInstanceState
determinando il lancio di una Questo accade a causa
NullPointerException.
della dimenticanza dei controlli sulla nullabilità dell’oggetto savedInstanceState.
{
override fun o n C r e a t e ( s a v e d I n s t a n c e S t a t e : Bundle ? ) KOTLIN
1 super . o n C r e a t e ( s a v e d I n s t a n c e S t a t e )
2 val i s S w i t c h e d O n : Boolean? = s a v e d I n s t a n c e S t a t e ? . g e t B o o l e a n ( )
" switch "
3 }
4 Listato 18: Operatore di chiamata sicura in Kotlin
20 21
Nell’esempio in Kotlin, invece, questo problema viene risolto utilizzando l’opera-
tore di chiamata sicura: se è nullo, allora viene restituito
savedInstanceState
altrimenti viene chiamato il metodo e restituito il risultato.
null, getBoolean
Da tenere a mente tuttavia che i riferimenti potenzialmente nulli possono re-
stituire un valore nullo, perciò è necessario (il compilatore Kotlin lo impone) che il
risultato dell’espressione sia di tipo (specificato esplicitamente o inferito
Boolean?
automaticamente), come indicato nell’esempio.
Questo operatore è utile anche durante le chiamate a catena. Se per esempio
Bob, un dipendente, può essere assegnato a un dipartimento (oppure no), il quale
a sua volta può possedere un altro dipendente come capo dipartimento, allora per
ottenere il nome del capo dipartimento di Bob (se presente), è possibile scrivere
13
quanto segue nel listato 19:
val name = bob ? . department ? . head ? . name
1 Listato 19: Operatore di chiamata sicura utilizzato in una catena
di chiamate
La precedente espressione restituisce quindi soltanto se rileva che un oggetto
null
è nullo; in questo modo si risparmia di controllare con molteplici la nullabilità
if
o meno di ogni oggetto.
Operatore elvis
L’operatore elvis (Elvis operator ) viene rappresentato per mezzo dei due caratteri
e si comporta nella maniera seguente: se l’operando di sinistra non è nullo,
?:
allora l’operatore di elvis lo restituisce come risultato, altrimenti restituisce il
secondo operando.
La sintassi di questo operatore è:
first operand ?: second operand
Nel listato 20 ne viene mostrato un esempio pratico:
13 Per maggiori informazioni visitare: http://archive.is/KtvGp
21
22 {
override fun o n C r e a t e ( s a v e d I n s t a n c e S t a t e : Bundle ? )
1 super . o n C r e a t e ( s a v e d I n s t a n c e S t a t e )
2 val i s S w i t c h e d O n : Boolean = s a v e d I n s t a n c e S t a t e ? . g e t B o o l e a n ( ) ? : f a l s e
" switch "
3 }
4 Listato 20: Operatore elvis in Kotlin
L’operatore elvis nell’esempio restituisce il valore dell’espressione savedInstanceSta-
se non è nullo, altrimenti re-
te?.getBoolean("switch") savedInstanceState
stituisce Questo operatore permette quindi di specificare un valore di
false.
default da restituire solo nel caso l’operando di sinistra non produca un risultato
idoneo (cioè non nullo).
Risulta inoltre importante sottolineare il fatto che in questo caso la variabile
è di tipo non è infatti più necessario specificarla come
isSwitchedOn Boolean:
in quanto l’operatore di elvis impedirà sempre che possa essere
Boolean?, null.
Questo operatore può essere utilizzato ovviamente anche congiuntamente a
catene di chiamate, ne è un buon esempio il listato 21:
val name = bob ? . department ? . head ? . name ? : " Jack "
1 Listato 21: Operatore elvis utilizzato insieme a una catena di chiamate
Operatore di asserzione non nulla
L’operatore di asserzione non nulla (not-null assertion operator ) viene indicato
con i tre caratteri e compie implicitamente un cast di una variabile potenzial-
!!.
mente nulla ad una non nulla. Il suo utilizzo è però fortemente sconsigliato, poiché
può essere fonte di errori a runtime e portare ad una NullPointerException.
Se il progra