Kotlin è un linguaggio di programmazione ampiamente usato dagli sviluppatori Android di tutto il mondo. Questo argomento è un Kotlin per iniziare a utilizzarla rapidamente.
Dichiarazione delle variabili
Kotlin utilizza due parole chiave diverse per dichiarare le variabili: val
e var
.
- Utilizza
val
per una variabile il cui valore non cambia mai. Non puoi riassegnare un valore a una variabile dichiarata utilizzandoval
. - Utilizza
var
per una variabile il cui valore può cambiare.
Nell'esempio riportato di seguito, count
è una variabile di tipo Int
a cui è stata assegnata una
valore iniziale di 10
:
var count: Int = 10
Int
è un tipo che rappresenta un numero intero, uno dei molti tipi numerici che
che possono essere rappresentati in Kotlin. Analogamente ad altre lingue, puoi anche utilizzare
Byte
, Short
, Long
, Float
e Double
in base ai tuoi dati numerici.
La parola chiave var
significa che puoi riassegnare i valori a count
in base alle esigenze. Per
Ad esempio, puoi modificare il valore di count
da 10
a 15
:
var count: Int = 10
count = 15
Alcuni valori però non sono pensati per essere modificati. Considera un String
chiamato
languageName
. Se vuoi assicurarti che languageName
contenga sempre un valore
di "Kotlin", puoi dichiarare languageName
utilizzando la parola chiave val
:
val languageName: String = "Kotlin"
Queste parole chiave ti consentono di indicare esplicitamente cosa puoi cambiare. Usali per
il tuo vantaggio, se necessario. Se un riferimento variabile deve essere riassegnabile,
dichiaralo var
. Altrimenti, usa val
.
Inferenza del tipo
Continuando con l'esempio precedente, quando assegni un valore iniziale a
languageName
, il compilatore Kotlin può dedurre il tipo in base al tipo di
il valore assegnato.
Poiché il valore di "Kotlin"
è di tipo String
, il compilatore deduce che
Anche languageName
è un String
. Tieni presente che Kotlin è un modello di tipo statico
lingua. Ciò significa che il tipo viene risolto al momento della compilazione e mai
modifiche.
Nell'esempio seguente, languageName
viene dedotto come String
, quindi non puoi
chiama qualsiasi funzione che non fa parte della classe String
:
val languageName = "Kotlin"
val upperCaseName = languageName.toUpperCase()
// Fails to compile
languageName.inc()
toUpperCase()
è una funzione che può essere richiamata solo per variabili di tipo
String
. Poiché il compilatore Kotlin ha dedotto languageName
come String
,
puoi chiamare toUpperCase()
. inc()
, tuttavia, è un operatore Int
, quindi non può essere chiamata su un String
. Approccio di Kotlin alla digitazione
l'inferenza fornisce sia concisione che sicurezza del tipo.
Nessuna sicurezza
In alcune lingue, una variabile del tipo di riferimento può essere dichiarata senza specificare un valore esplicito iniziale. In questi casi, le variabili di solito contengono un valore valore. Per impostazione predefinita, le variabili Kotlin non possono contenere valori nulli. Ciò significa che il seguente snippet non è valido:
// Fails to compile
val languageName: String = null
Affinché una variabile possa contenere un valore nullo, deve essere di tipo null. Puoi
specifica una variabile come annullabile aggiungendo il suffisso al tipo con ?
, come mostrato
nel seguente esempio:
val languageName: String? = null
Con un tipo String?
, puoi assegnare un valore String
o null
a
languageName
.
Devi gestire attentamente le variabili nullable o rischiare un attacco temuto
NullPointerException
. In Java, ad esempio, se tenti di richiamare un metodo
in corrispondenza di un valore null, il programma si arresta in modo anomalo.
Kotlin fornisce una serie di meccanismi per lavorare in sicurezza con valori nulli. come la codifica one-hot delle variabili categoriche. Per ulteriori informazioni, vedi Pattern Kotlin comuni in Android: nullità.
Condizionali
Kotlin presenta diversi meccanismi per implementare la logica condizionale. Il più
comune di queste è l'istruzione if-else. Se un'espressione è racchiusa
Le parentesi accanto a una parola chiave if
hanno come risultato true
, quindi il codice all'interno
ramo (ovvero il codice immediatamente successivo avvolto in
parentesi graffe) viene eseguito. In caso contrario, viene eseguito il codice all'interno del ramo else
.
if (count == 42) {
println("I have the answer.")
} else {
println("The answer eludes me.")
}
Puoi rappresentare più condizioni utilizzando else if
. Ciò ti consente di rappresentare
più granulare e complessa all'interno di una singola istruzione condizionale, come
nell'esempio seguente:
if (count == 42) {
println("I have the answer.")
} else if (count > 35) {
println("The answer is close.")
} else {
println("The answer eludes me.")
}
Le istruzioni condizionali sono utili per rappresentare la logica stateful, ma puoi
ti capita di ripetere te stesso quando li scrivi. Nell'esempio precedente,
è sufficiente stampare String
in ogni ramo. Per evitare questa ripetizione, Kotlin offre
espressioni condizionali. L'ultimo esempio può essere riscritto come segue:
val answerString: String = if (count == 42) {
"I have the answer."
} else if (count > 35) {
"The answer is close."
} else {
"The answer eludes me."
}
println(answerString)
implicitamente, ogni ramo condizionale restituisce il risultato dell'espressione nella relativa
nell'ultima riga, pertanto non è necessario utilizzare una parola chiave return
. Poiché il risultato
tutti e tre i rami sono di tipo String
. Il risultato dell'espressione if-else è
anch'essi di tipo String
. In questo esempio, a answerString
viene assegnato un numero
dal risultato dell'espressione if-else. L'inferenza del tipo può essere utilizzata
omettere la dichiarazione di tipo esplicita per answerString
, ma spesso è una buona
di includerli per chiarezza.
Man mano che la complessità della tua affermazione condizionale cresce, potresti prendere in considerazione sostituendo l'espressione if-else con un'espressione quando, come illustrato nell'esempio seguente:
val answerString = when {
count == 42 -> "I have the answer."
count > 35 -> "The answer is close."
else -> "The answer eludes me."
}
println(answerString)
Ogni ramo in un'espressione when
è rappresentato da una condizione, una freccia
(->
) e un risultato. Se la condizione sul lato sinistro della freccia
restituisce true, il risultato dell'espressione sul lato destro è
restituito. Tieni presente che l'esecuzione non passa da un ramo all'altro.
Il codice nell'esempio dell'espressione when
è funzionalmente equivalente a quello in
dell'esempio precedente, ma è probabilmente più facile da leggere.
I condizionali di Kotlin evidenziano una delle sue funzionalità più potenti, trasmissione intelligente. Anziché utilizzare l'operatore di chiamata sicura o il valore not-null di asserzione per lavorare con valori nulli, puoi invece verificare se un contiene un riferimento a un valore nullo utilizzando un'istruzione condizionale, come come mostrato nell'esempio seguente:
val languageName: String? = null
if (languageName != null) {
// No need to write languageName?.toUpperCase()
println(languageName.toUpperCase())
}
All'interno del ramo condizionale, languageName
potrebbe essere considerato un elemento senza valori null.
Kotlin è abbastanza intelligente da riconoscere che la condizione per l'esecuzione del ramo
è che languageName
non contiene un valore nullo, quindi non devi trattare
languageName
come null all'interno di quel ramo. Questa trasmissione intelligente funziona per
controlli
controlli dei tipi,
o qualsiasi condizione che soddisfi un
contratto.
Funzioni
Puoi raggruppare una o più espressioni in una funzione. Anziché ripetere la stessa serie di espressioni ogni volta che hai bisogno di un risultato, puoi le espressioni in una funzione e richiamarla al loro posto.
Per dichiarare una funzione, utilizza la parola chiave fun
seguita dal nome della funzione.
Successivamente, definisci i tipi di input accettati dalla funzione, se presenti, e dichiara
il tipo di output che restituisce. Il corpo di una funzione è il punto in cui
espressioni che vengono richiamate quando viene richiamata la tua funzione.
Basandoti sugli esempi precedenti, ecco una funzione di Kotlin completa:
fun generateAnswerString(): String {
val answerString = if (count == 42) {
"I have the answer."
} else {
"The answer eludes me"
}
return answerString
}
La funzione nell'esempio precedente ha il nome generateAnswerString
. it
non richiede input. Restituisce un risultato di tipo String
. Per chiamare un
, utilizza il nome, seguito dall'operatore di chiamata (()
). Nella
Nell'esempio riportato di seguito, la variabile answerString
viene inizializzata con il risultato
generateAnswerString()
.
val answerString = generateAnswerString()
Le funzioni possono assumere argomenti come input, come mostrato nell'esempio seguente:
fun generateAnswerString(countThreshold: Int): String {
val answerString = if (count > countThreshold) {
"I have the answer."
} else {
"The answer eludes me."
}
return answerString
}
Quando dichiari una funzione, puoi specificare un numero qualsiasi di argomenti e la loro
di testo. Nell'esempio precedente, generateAnswerString()
utilizza un argomento denominato
countThreshold
di tipo Int
. All'interno della funzione, puoi fare riferimento
utilizzando il suo nome.
Quando chiami questa funzione, devi includere un argomento all'interno della funzione le parentesi della chiamata:
val answerString = generateAnswerString(42)
Semplificare le dichiarazioni di funzione
generateAnswerString()
è una funzione piuttosto semplice. La funzione dichiara un
e restituisce immediatamente la variabile. Quando il risultato di una singola espressione è
da una funzione, puoi saltare la dichiarazione di una variabile locale
che restituisce il risultato dell'espressione if-else contenuta nella funzione, come
come mostrato nell'esempio seguente:
fun generateAnswerString(countThreshold: Int): String {
return if (count > countThreshold) {
"I have the answer."
} else {
"The answer eludes me."
}
}
Puoi anche sostituire la parola chiave "return" con l'operatore di assegnazione:
fun generateAnswerString(countThreshold: Int): String = if (count > countThreshold) {
"I have the answer"
} else {
"The answer eludes me"
}
Funzioni anonime
Non tutte le funzioni hanno bisogno di un nome. Alcune funzioni sono identificate in modo più diretto i relativi input e output. Queste sono chiamate funzioni anonime. Tu può tenere un riferimento a una funzione anonima, utilizzando questo riferimento la funzione anonima in un secondo momento. Puoi anche passare il riferimento un'applicazione, come con altri tipi di riferimenti.
val stringLengthFunc: (String) -> Int = { input ->
input.length
}
Come le funzioni con nome, le funzioni anonime possono contenere un numero qualsiasi di espressioni. Il valore restituito della funzione è il risultato dell'espressione finale.
Nell'esempio precedente, stringLengthFunc
contiene un riferimento a un indirizzo
funzione che prende String
come input e restituisce la lunghezza dell'input
String
come output di tipo Int
. Per questo motivo, il tipo di funzione è
indicato come (String) -> Int
. Questo codice, tuttavia, non richiama la funzione.
Per recuperare il risultato di una funzione, devi richiamarla come faresti con
funzione con nome. Devi fornire un String
quando chiami stringLengthFunc
, come
come mostrato nell'esempio seguente:
val stringLengthFunc: (String) -> Int = { input ->
input.length
}
val stringLength: Int = stringLengthFunc("Android")
Funzioni di ordine superiore
Una funzione può prendere un'altra funzione come argomento. Funzioni che utilizzano altre come argomenti sono chiamate funzioni di ordine superiore. Questo pattern è è utile per comunicare tra i componenti nello stesso modo in cui si utilizza un di callback in Java.
Ecco un esempio di funzione di ordine superiore:
fun stringMapper(str: String, mapper: (String) -> Int): Int {
// Invoke function
return mapper(str)
}
La funzione stringMapper()
accetta un valore String
insieme a una funzione che
ricava un valore Int
da un String
che passi in lì.
Puoi chiamare stringMapper()
passando un String
e una funzione che
soddisfa l'altro parametro di input, ovvero una funzione che prende String
come
un input e output di un Int
, come mostrato nell'esempio seguente:
stringMapper("Android", { input ->
input.length
})
Se la funzione anonima è l'ultimo parametro definito su una funzione, puoi passala fuori tra le parentesi utilizzate per richiamare la funzione, come mostrato nell' nell'esempio seguente:
stringMapper("Android") { input ->
input.length
}
Le funzioni anonime sono disponibili in tutta la libreria standard Kotlin. Per ulteriori informazioni, vedi Funzioni di ordine superiore e Lambdas.
Classi
Tutti i tipi indicati finora sono integrati nella programmazione Kotlin
lingua. Se vuoi aggiungere il tuo tipo personalizzato, puoi definire una classe
utilizzando la parola chiave class
, come mostrato nell'esempio seguente:
class Car
Proprietà
Le classi rappresentano gli stati mediante le proprietà. R
property è
una variabile a livello di classe che può includere un getter, un setter e un campo di supporto.
Poiché un'auto ha bisogno delle ruote per guidare, puoi aggiungere un elenco di oggetti Wheel
come
di Car
, come mostrato nell'esempio seguente:
class Car {
val wheels = listOf<Wheel>()
}
Tieni presente che wheels
è un public val
, il che significa che è possibile accedere a wheels
all'esterno del corso Car
e non può essere riassegnato. Se desideri ottenere
di Car
, devi prima chiamare il relativo costruttore. Da qui puoi
accedere alle sue proprietà accessibili.
val car = Car() // construct a Car
val wheels = car.wheels // retrieve the wheels value from the Car
Se vuoi personalizzare le tue ruote, puoi definire un costruttore personalizzato specifica come vengono inizializzate le proprietà delle classi:
class Car(val wheels: List<Wheel>)
Nell'esempio precedente, il costruttore della classe prende List<Wheel>
come
dell'argomento costruttore e lo utilizza per inizializzare il suo wheels
proprietà.
Funzioni di classe e incapsulamento
Le classi usano funzioni per modellare il comportamento. Le funzioni possono modificare lo stato, per esporre solo i dati che vuoi. Questo controllo dell'accesso fa parte un concetto più ampio orientato agli oggetti noto come incapsulamento.
Nell'esempio seguente, la proprietà doorLock
viene mantenuta privata per qualsiasi elemento
al di fuori della classe Car
. Per aprire l'auto, devi chiamare il unlockDoor()
di una funzione che trasmette una chiave valida, come illustrato nell'esempio seguente:
class Car(val wheels: List<Wheel>) {
private val doorLock: DoorLock = ...
fun unlockDoor(key: Key): Boolean {
// Return true if key is valid for door lock, false otherwise
}
}
Se vuoi personalizzare il modo in cui viene fatto riferimento a una proprietà, puoi fornire un
getter e setter personalizzati. Ad esempio, se vuoi esporre la proprietà
getter limitando l'accesso al relativo setter, puoi designarlo come
private
:
class Car(val wheels: List<Wheel>) {
private val doorLock: DoorLock = ...
var gallonsOfFuelInTank: Int = 15
private set
fun unlockDoor(key: Key): Boolean {
// Return true if key is valid for door lock, false otherwise
}
}
Con una combinazione di proprietà e funzioni, puoi creare classi modellare tutti i tipi di oggetti.
Interoperabilità
Una delle caratteristiche più importanti di Kotlin è la sua interoperabilità fluida con Java. Poiché il codice Kotlin si compila in bytecode JVM, il codice Kotlin può chiamare direttamente nel codice Java e viceversa. Ciò significa che puoi sfruttare le librerie Java esistenti direttamente da Kotlin. Inoltre, la maggior parte dei Le API Android sono scritte in Java e puoi chiamarle direttamente da Kotlin.
Passaggi successivi
Kotlin è un linguaggio flessibile e pragmatico con un supporto e uno slancio crescenti. Me ti invitiamo a provarlo, se non l'hai ancora fatto. Per i passaggi successivi, dai un'occhiata nella documentazione ufficiale di Kotlin insieme alla guida su come presentare domanda pattern Kotlin comuni nelle tue app per Android.