Kotlin: variabili, tipi e conversioni tra tipi

Variabili e tipi

In Kotlin abbiamo due diversi tipi di variabili:

  • quelle che indicano un riferimento immutabile e non sono modificabili, dichiarate con la keyword val,
  • quelle il cui valore può essere modificato nel corso del programma (runtime), dichiarate con la keyword var.

Esempi di dichiarazione di variabili sono:

val animale = "Gatto"
var peso = 3

In questo caso, la variabile animale è costante mentre peso può essere modificato runtime. Nell’esempio riportato, il tipo delle due variabili viene dedotto da Kotlin sulla base del valore riportato dopo il simbolo =. In programmazione questo tipo di assegnazione è chiamato (local) type inference. Questo vuol dire che alcune informazioni, come in questo caso il tipo di una variabile, vengono decisi dal compilatore.

Ovviamente possiamo specificare anche il tipo della variabile utilizzando le seguenti keyword:

  • Number: un generico numero il cui tipo è dedotto via type inference. Maggiori dettagli sono riportati nel paragrafo dedicato.
  • Boolean: valore booleano “true” o “false”. Esempio di utilizzo di questo tipo: true
  • Char: strettamente un carattere. Esempio di utilizzo: ‘a’ oppure per caratteri Unicode si utilizza ‘\uFF00′.
  • String: un array di caratteri. Esempio di utilizzo: “abcd 1234”. Maggiori dettagli sono riportati nel paragrafo dedicato.
  • Array: un array generico il cui tipo è dedotto via type inference. Esempio di utilizzo Array(5){}. Maggiori dettagli sono riportati nel paragrafo dedicato.

Nel caso in cui vogliamo specificare il tipo, esempi di dichiarazioni di variabili sono:

val constNumberVar : Number = 3.2f
var booleanVar : Boolean = true
val constCharVar : Char = 'a'
var stringVar : String = "esempio" 
val constArray = Array(5) { i -> 5L }

Facciamo notare che in Kotlin, così come in Java, i tipi di variabili sono classi. Questo significa che, a differenza di altri linguaggi di programmazione, è nota la massima memoria che deve occupare il nostro dato per essere immagazzinato in quel tipo (8bit, 32 bit, 64 bit, …) ma questa non coincide con la memoria effettiva destinata dal compilatore al programma. Ad esempio, un intero a 32 bit potrà essere memorizzato in una variabile di tipo Int ma tale variabile occuperà in memoria non 4 byte ma 16 byte.

Per maggiori informazioni sui tipi base utilizzati in Kotlin visitate https://kotlinlang.org/docs/basic-types.html .

Number

La classe Number è la classe astratta da cui derivano tutti i numeri, siano essi interi o a virgola mobile. Usare il tipo Number è così l’unico modo per memorizzare in una sola variabile diversi tipi numerici. Oltre alla classe Number esistono anche i tipi base specifici (primitive):

  • Per i numeri interi ci sono quattro tipi diversi, ciascuno con la propria dimensione e range. Questi diventano otto se si considera anche la versione senza segno:
    • ULong: numero intero senza segno a 64 bit [0 ; 2^64 – 1]. Esempio di utilizzo di questo tipo: 3UL
    • Long: numero intero con segno a 64 bit [-9,223,372,036,854,775,808 ; 9,223,372,036,854,775,807]. Esempio di utilizzo di questo tipo: 3L
    • UInt: numero intero senza segno a 32 bit [0 ; 2^32 – 1]. Esempio di utilizzo di questo tipo: 3U
    • Int: numero intero con segno a 32 bit [-2,147,483,648 ; 2,147,483,647]. Esempio di utilizzo di questo tipo: 3
    • UShort: numero intero senza segno a 16 bit [0 ; 65535]. Non viene mai usato via type inference
    • Short: numero intero con segno a 16 bit [-32768 ; 32767]. Non viene mai usato via type inference
    • UByte: numero intero senza segno a 8 bit [0 ; 255]. Non viene mai usato via type inference
    • Byte: numero intero con segno a 8 bit [-128 ; 127]. Non viene mai usato via type inference
  • Per i numeri reali, Kotlin fornisce due tipi di numeri a virgola mobile (floating-point): Float e Double. In accordo con lo standard IEEE 754 standard, i tipi a virgola mobile differiscono da loro decimal place, definito come quante cifre decimale la variabile può memorizzare. Il tipo Float riflette il tipo IEEE 754 single precision, mentre il tipo Double fornisce una double precision:
    • Double: numero reale a 64 bit [54 bit significativi, 11 bit per l’esponente, 15-16 decimali]. Esempio di utilizzo di questo tipo: 1.24
    • Float: numero reale a 32 bit [24 bit significativi, 8 bit per l’esponente, 6-7 decimali]. Esempio di utilizzo di questo tipo: 1.24f o 1.24F

Per gli interi è possibile utilizzare anche il formato binario (ad esempio 0b00001011) o esadecimale (ad esempio 0x0F). Non è supportata il formato ottale. Inoltre è possibile utilizzare il simbolo _ per separare set di numeri al fine di rendere più leggibile il codice. Esempi sono:

  • 1_000_000
  • 1234_5678_9012_3456L
  • 0xFF_EC_DE_5E
  • 0b11010010_01101001_10010100_10010010

A tutte le variabili inizializzate con valori interi tali da non superare il massimo valore del tipo Int, viene associato via type inference il tipo Int. In caso contrario, il tipo associato è Long. La lista di tutte le funzioni e proprietà dei dati di tipo Number e la loro compatibilità con le librerie comuni di Kotlin indipendenti dall’architettura (common) e quelle dipendenti dall’architettura utilizzata (native, JVM e JS) è riportata in https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-number/

Conversione tra tipi

In Kotlin non si può assegnare ad una variabile un valore di un tipo diverso se non nel caso Number. Quindi non è possibile assegnare un tipo di dato più piccolo (come un Long) ad una struttura dati più grande (come un Double) effettuando quella che prende il nome di conversione implicita (implicit conversion) supportata invece da alcuni linguaggi di programmazione come lo stesso Java. In ogni caso in Kotlin è supportata la conversione esplicita (explicit conversion) da una struttura data ad un’altra (anche da una struttura grande ad una piccola). Questo si può fare attraverso una delle seguenti funzioni helper:

  • toByte: converte una variabile (value) di un determinato tipo in Byte. Esempio di utilizzo value.toByte()
  • toUByte: converte una variabile (value) di un determinato tipo in UByte. Esempio di utilizzo value.toUByte()
  • toShort: converte una variabile (value) di un determinato tipo in Short. Esempio di utilizzo value.toShort()
  • toUShort: converte una variabile (value) di un determinato tipo in UShort. Esempio di utilizzo value.toUShort()
  • toInt: converte una variabile (value) di un determinato tipo in Int. Esempio di utilizzo value.toInt()
  • toUInt: converte una variabile (value) di un determinato tipo in UInt. Esempio di utilizzo value.toUInt()
  • toLong: converte una variabile (value) di un determinato tipo in Long. Esempio di utilizzo value.toLong()
  • toULong: converte una variabile (value) di un determinato tipo in ULong. Esempio di utilizzo value.toULong()
  • toFloat: converte una variabile (value) di un determinato tipo in Float. Esempio di utilizzo value.toFloat()
  • toDouble: converte una variabile (value) di un determinato tipo in Double. Esempio di utilizzo value.toDouble()
  • toChar: converte una variabile (value) di un determinato tipo in Char. Esempio di utilizzo value.toChar()

come si vede non c’è la conversione a booleano. Nel caso in cui non si riesca ad eseguire la conversione correttamente, Kotlin restituisce l’eccezione NumberFormatException. Per evitare questo è possibile chiamare le versioni helper che, in caso di errore nella conversione restituiscono il valore null:

  • toByteOrNull
  • toUByteOrNull
  • toShortOrNull
  • toUShortOrNull
  • toIntOrNull
  • toUIntOrNull
  • toLongOrNull
  • toULongOrNull
  • toFloatOrNull
  • toDoubleOrNull

non è supportata la versione toCharOrNull. Esiste anche un modo non sicuro (unsafe cast) di convertire un tipo in un’altro attraverso l’operatore as. Esempio di utilizzo: value as Int.

Nel caso degli array, in Kotlin questi sono invarianti e quindi non si può attribuire ad un array un array di un altro tipo. Non esistono funzioni che permettono la conversione tra due diversi tipi di array. Quello che è possibile fare è fare un ciclo sugli elementi, convertirli uno a uno, ed aggiungerli ad un nuovo array vuoto del tipo desiderato.

Esiste infine l’operatore is che può essere utilizzato per effettuare un check sul tipo di una variabile (value). Esempio di utilizzo: value is Int . Se value è intero torna true, altrimenti false. Per maggiori informazioni visitate il sito https://kotlinlang.org/docs/typecasts.html

Potrebbero interessarti anche...

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *

Questo sito usa Akismet per ridurre lo spam. Scopri come i tuoi dati vengono elaborati.