Impara il linguaggio di programmazione Kotlin

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 utilizzando val.
  • 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.