Questo codelab fa parte del Kotlin Bootcamp for Programs. Otterrai il massimo valore da questo corso se lavori in sequenza nei codelab. A seconda delle tue conoscenze, potresti essere in grado di scorrere alcune sezioni. Questo corso è rivolto ai programmatori che conoscono una lingua orientata agli oggetti e vogliono imparare il kotlin.
Introduzione
In questo codelab ti verranno presentate diverse funzionalità utili in Kotlin, tra cui coppie, raccolte e funzioni di estensione.
Anziché creare un'unica app di esempio, le lezioni di questo corso sono state concepite per sviluppare le tue conoscenze, ma sono semi-indipendenti gli uni dagli altri per esplorare le sezioni che conosci. Per collegare tutti questi esempi, molti sono basati su un acquario. E se vuoi vedere l'intera storia dell'acquario, dai un'occhiata al Bootcamp Kotlin per programmatoriCorso Udacity.
Informazioni importanti
- La sintassi delle funzioni, delle classi e dei metodi di Kotlin
- Come utilizzare REPL (Read-Eval-Print Loop) di IntelliJ IDEA di Kotlin
- Come creare una nuova classe in IntelliJ IDEA ed eseguire un programma
Obiettivi didattici
- Come utilizzare coppie e triple
- Scopri di più sulle collezioni
- Definizione e utilizzo di costanti
- Scrittura delle funzioni delle estensioni
In questo lab proverai a:
- Scopri di più su coppie, triple e mappe hash in REPL
- Scopri i diversi modi di organizzare le costanti
- Scrivere una funzione estensione e una proprietà estensione
In questa attività imparerai a coppie e triple e a distruggerle. Le coppie e le triple sono classi di dati predefinite per 2 o 3 articoli generici. Questo può essere utile, ad esempio, perché una funzione restituisca più di un valore.
Supponiamo di avere un List
di pesce e una funzione isFreshWater()
per verificare se si trattava di un pesce d'acqua dolce o di acqua salata. List.partition()
restituisce due elenchi, uno con gli elementi per i quali la condizione è pari a true
e l'altro per gli elementi in cui la condizione è pari a false
.
val twoLists = fish.partition { isFreshWater(it) }
println("freshwater: ${twoLists.first}")
println("saltwater: ${twoLists.second}")
Passaggio 1: crea un paio di coppie e un triplo
- Apri il REPL (Strumenti > Kotlin > Kotlin REPL).
- Crea una coppia, associando un'apparecchiatura all'utilizzo, quindi stampa i valori. Puoi creare una coppia creando un'espressione che colleghi due valori, ad esempio due stringhe, con la parola chiave
to
, quindi utilizza.first
o.second
per fare riferimento a ciascun valore.
val equipment = "fish net" to "catching fish"
println("${equipment.first} used for ${equipment.second}")
⇒ fish net used for catching fish
- Crea una tripla e stampala con
toString()
, quindi convertila in un elenco contoList()
. Puoi creare una tripla utilizzandoTriple()
con 3 valori. Utilizza.first
,.second
e.third
per fare riferimento a ciascun valore.
val numbers = Triple(6, 9, 42)
println(numbers.toString())
println(numbers.toList())
⇒ (6, 9, 42) [6, 9, 42]
Gli esempi precedenti utilizzano lo stesso tipo per tutte le parti della coppia o della tripla, ma ciò non è obbligatorio. Le parti possono essere una stringa, un numero o un elenco, ad esempio un'altra coppia o tripla.
- Crea una coppia in cui la prima parte della coppia stessa è una coppia.
val equipment2 = ("fish net" to "catching fish") to "equipment"
println("${equipment2.first} is ${equipment2.second}\n")
println("${equipment2.first.second}")
⇒ (fish net, catching fish) is equipment ⇒ catching fish
Passaggio 2: elimina alcune coppie e tre triple
La separazione di coppie e triple nelle parti viene chiamata distruttività. Assegna la coppia o la tripla al numero corretto di variabili e Kotlin assegnerà il valore di ogni parte in ordine.
- Elimina una coppia e stampa i valori.
val equipment = "fish net" to "catching fish"
val (tool, use) = equipment
println("$tool is used for $use")
⇒ fish net is used for catching fish
- Elimina la tripla e stampa i valori.
val numbers = Triple(6, 9, 42)
val (n1, n2, n3) = numbers
println("$n1 $n2 $n3")
⇒ 6 9 42
Tieni presente che la strutturazione di coppie e triple funziona come per le classi di dati, trattate in un codelab precedente.
In questa attività troverai ulteriori informazioni sulle raccolte, tra cui gli elenchi e un nuovo tipo di raccolta, le mappe di hash.
Passaggio 1: scopri di più sugli elenchi
- Gli elenchi e gli elenchi modificabili sono stati introdotti in una lezione precedente. Sono una struttura di dati molto utili, quindi Kotlin fornisce una serie di funzioni integrate per gli elenchi. Esamina questo elenco parziale di funzioni per gli elenchi. Le schede complete sono disponibili nella documentazione di Kotlin per
List
eMutableList
.
Funzione | Scopo |
| Aggiungi un elemento all'elenco modificabile. |
| Rimuovi un elemento da un elenco modificabile. |
| Restituisce una copia dell'elenco con gli elementi in ordine inverso. |
| Restituisci |
| Restituisce una parte dell'elenco, dal primo indice fino a escludere il secondo. |
- Ancora in esecuzione nel REPL, crea un elenco di numeri e chiama il numero
sum()
. In questo modo vengono sommati tutti gli elementi.
val list = listOf(1, 5, 3, 4)
println(list.sum())
⇒ 13
- Crea un elenco di stringhe e somma l'elenco.
val list2 = listOf("a", "bbb", "cc")
println(list2.sum())
⇒ error: none of the following functions can be called with the arguments supplied:
- Se l'elemento non è in grado di sommare direttamente
List
, ad esempio una stringa, puoi specificare come sommarlo utilizzando.sumBy()
con una funzione lambda, ad esempio con la lunghezza di ogni stringa. Il nome predefinito per un argomento lambda èit
e quiit
si riferisce a ogni elemento dell'elenco quando l'elenco viene barrato.
val list2 = listOf("a", "bbb", "cc")
println(list2.sumBy { it.length })
⇒ 6
- Con le liste puoi fare molto di più. Un modo per vedere la funzionalità disponibile è creare un elenco in IntelliJ IDEA, aggiungere il punto e poi controllare l'elenco di completamento automatico nella descrizione comando. Questa soluzione è valida per qualsiasi oggetto. Provalo con una lista.
- Scegli
listIterator()
dall'elenco, quindi seguilo con un'istruzionefor
e stampa tutti gli elementi separati da spazi.
val list2 = listOf("a", "bbb", "cc")
for (s in list2.listIterator()) {
println("$s ")
}
⇒ a bbb cc
Passaggio 2: prova le mappe hash
In Kotlin puoi mappare praticamente qualsiasi cosa con hashMapOf()
. Le mappe hash sono come un elenco di coppie, in cui il primo valore funge da chiave.
- Crea una mappa hash che corrisponda ai sintomi, alle chiavi e alle malattie dei pesci, ovvero ai valori.
val cures = hashMapOf("white spots" to "Ich", "red sores" to "hole disease")
- Puoi quindi recuperare il valore della malattia in base alla chiave del sintomo, utilizzando
get()
o parentesi quadre più brevi[]
.
println(cures.get("white spots"))
⇒ Ich
println(cures["red sores"])
⇒ hole disease
- Prova a specificare un sintomo che non è presente sulla mappa.
println(cures["scale loss"])
⇒ null
Se nella mappa non è presente una chiave, il tentativo di restituire la malattia corrispondente restituisce null
. In base ai dati della mappa, può capitare che non venga trovata una corrispondenza per una chiave possibile. In questi casi, Kotlin fornisce la funzione getOrDefault()
.
- Prova a cercare una chiave che non ha corrispondenze, usando
getOrDefault()
.
println(cures.getOrDefault("bloating", "sorry, I don't know"))
⇒ sorry, I don't know
Se non devi solo restituire un valore, Kotlin fornisce la funzione getOrElse()
.
- Modifica il codice per utilizzare
getOrElse()
anzichégetOrDefault()
.
println(cures.getOrElse("bloating") {"No cure for this"})
⇒ No cure for this
Anziché restituire un semplice valore predefinito, viene eseguito qualsiasi codice tra le parentesi graffe {}
. Nell'esempio, else
restituisce semplicemente una stringa, ma potrebbe essere interessante trovare una pagina web con una cura e restituirla.
Proprio come mutableListOf
, puoi anche creare una mutableMapOf
. Una mappa modificabile consente di inserire e rimuovere elementi. Muable significa cambiare, immutabile significa cambiare.
- Crea una mappa dell'inventario che può essere modificata, mappando una stringa dell'apparecchiatura al numero di elementi. Creala con una rete per pesci, quindi aggiungi 3 scrubber per serbatoi nell'inventario con
put()
e rimuovi la rete per i pesci conremove()
.
val inventory = mutableMapOf("fish net" to 1)
inventory.put("tank scrubber", 3)
println(inventory.toString())
inventory.remove("fish net")
println(inventory.toString())
⇒ {fish net=1, tank scrubber=3}{tank scrubber=3}
In questa attività imparerai le costanti in Kotlin e i diversi modi di organizzarle.
Passaggio 1: scopri di più su cost e val
- Nel REPL, prova a creare una costante numerica. In Kotlin puoi creare costanti di primo livello e assegnarle un valore al momento della compilazione utilizzando
const val
.
const val rocks = 3
Il valore è assegnato e non può essere modificato, il che sembra molto simile a una dichiarazione val
regolare. Quindi qual è la differenza tra const val
e val
? Il valore di const val
è determinato al momento della compilazione, mentre il valore di val
viene determinato durante l'esecuzione del programma. Ciò significa che val
può essere assegnato a una funzione in fase di esecuzione.
Ciò significa che val
può essere assegnato un valore da una funzione, ma const val
non può farlo.
val value1 = complexFunctionCall() // OK
const val CONSTANT1 = complexFunctionCall() // NOT ok
Inoltre, const val
funziona solo al livello superiore e nelle classi singole dichiarate con object
, non con le classi normali. Puoi utilizzarlo per creare un file o un oggetto singleton che contiene solo costanti e importarle in base alle necessità.
object Constants {
const val CONSTANT2 = "object constant"
}
val foo = Constants.CONSTANT2
Passaggio 2: crea un oggetto companion
Kotlin non ha un concetto di costanti a livello di classe.
Per definire le costanti all'interno di una classe, devi aggregarle agli oggetti companion dichiarati con la parola chiave companion
. L'oggetto companion è sostanzialmente un oggetto singleton all'interno della classe.
- Crea una classe con un oggetto companion contenente una costante stringa.
class MyClass {
companion object {
const val CONSTANT3 = "constant in companion"
}
}
La differenza di base tra gli oggetti companion e gli oggetti normali è:
- Gli oggetti companion vengono inizializzati dal costruttore statico della classe che la contiene, ovvero quando vengono creati.
- Gli oggetti standard vengono inizializzati tramite laziale al primo accesso a tale oggetto, ovvero quando vengono utilizzati per la prima volta.
ma c'è dell'altro, ma tutto ciò che devi sapere per il momento è racchiudere le costanti nelle classi di un oggetto companion.
In questa attività imparerai a estendere il comportamento dei corsi. Scrivere funzioni di utilità per estendere il comportamento di una classe è molto comune. Kotlin fornisce una comoda sintassi per dichiarare queste funzioni di utilità: le estensioni.
Le funzioni di estensione ti consentono di aggiungere funzioni a una classe esistente senza dover accedere al relativo codice sorgente. ad esempio in un file Extensions.kt che fa parte del pacchetto. Ciò non modifica effettivamente la classe, ma ti consente di utilizzare la annotazione del punto quando chiami la funzione sugli oggetti di tale classe.
Passaggio 1: scrivi una funzione dell'estensione
- Ancora in esecuzione nel REPL, scrivi una semplice funzione estensione,
hasSpaces()
, per verificare se una stringa contiene spazi. Il nome della funzione è preceduto dal prefisso della classe in cui opera. All'interno della funzione,this
si riferisce all'oggetto su cui viene chiamata eit
si riferisce all'iteratore nella chiamatafind()
.
fun String.hasSpaces(): Boolean {
val found = this.find { it == ' ' }
return found != null
}
println("Does it have spaces?".hasSpaces())
⇒ true
- Puoi semplificare la funzione
hasSpaces()
. Ilthis
non è esplicitamente necessario e la funzione può essere ridotta a una singola espressione e restituita, quindi non sono più necessarie le parentesi graffe{}
attorno ad esso.
fun String.hasSpaces() = find { it == ' ' } != null
Passaggio 2: scopri le limitazioni delle estensioni
Le funzioni di estensione hanno accesso solo all'API pubblica della classe che si estendono. Impossibile accedere alle variabili private
.
- Prova ad aggiungere funzioni di estensione a una proprietà contrassegnata come
private
.
class AquariumPlant(val color: String, private val size: Int)
fun AquariumPlant.isRed() = color == "red" // OK
fun AquariumPlant.isBig() = size > 50 // gives error
⇒ error: cannot access 'size': it is private in 'AquariumPlant'
- Esamina il codice qui sotto e scopri che cosa verrà stampato.
open class AquariumPlant(val color: String, private val size: Int)
class GreenLeafyPlant(size: Int) : AquariumPlant("green", size)
fun AquariumPlant.print() = println("AquariumPlant")
fun GreenLeafyPlant.print() = println("GreenLeafyPlant")
val plant = GreenLeafyPlant(size = 10)
plant.print()
println("\n")
val aquariumPlant: AquariumPlant = plant
aquariumPlant.print() // what will it print?
⇒ GreenLeafyPlant AquariumPlant
plant.print()
stampa GreenLeafyPlant
. Anche aquariumPlant.print()
potrebbe stampare GreenLeafyPlant
, perché gli è stato assegnato il valore plant
. Tuttavia, il tipo viene risolto al momento della compilazione, quindi AquariumPlant
viene stampato.
Passaggio 3: aggiungi una proprietà estensione
Oltre alle funzioni delle estensioni, Kotlin ti consente anche di aggiungere proprietà delle estensioni. Come per le estensioni, puoi specificare la classe che stai estendendo, seguita da un punto e dal nome della proprietà.
- Ancora in fase di elaborazione nel REPL, aggiungi una proprietà dell'estensione
isGreen
aAquariumPlant
, che ètrue
se il colore è verde.
val AquariumPlant.isGreen: Boolean
get() = color == "green"
È possibile accedere alla proprietà isGreen
proprio come una proprietà normale; quando si accede, il getter per isGreen
viene chiamato per ottenere il valore.
- Stampa la proprietà
isGreen
per la variabileaquariumPlant
e osserva il risultato.
aquariumPlant.isGreen
⇒ res4: kotlin.Boolean = true
Passaggio 4: scopri i destinatari nulli
La classe che espandi si chiama destinatario ed è possibile rendere nulla tale classe. In tal caso, la variabile this
utilizzata nel corpo può essere null
, pertanto assicurati di testarla. Potresti prendere un ricevitore senza valore se prevedi che i chiamanti chiamino il tuo metodo di estensione per le variabili non visibili o se vuoi fornire un comportamento predefinito quando la funzione viene applicata a null
.
- Ancora in fase di elaborazione nel REPL, definisci un metodo
pull()
che accetti un ricevitore nullable. Viene indicato con un punto interrogativo?
dopo il tipo, prima del punto. All'interno del corpo, puoi verificare sethis
non ènull
utilizzando il punto interrogativo-applica-?.apply.
fun AquariumPlant?.pull() {
this?.apply {
println("removing $this")
}
}
val plant: AquariumPlant? = null
plant.pull()
- In questo caso non viene generato alcun output quando esegui il programma. Poiché
plant
ènull
, l'elementoprintln()
interno non viene chiamato.
Le funzioni delle estensioni sono molto potenti e la maggior parte della libreria standard Kotlin viene implementata come funzioni delle estensioni.
In questa lezione hai imparato di più sulle collezioni, hai imparato sulle costanti e hai imparato la potenza delle funzioni e delle proprietà delle estensioni.
- È possibile utilizzare coppie e triple per restituire più di un valore da una funzione. Ad esempio:
val twoLists = fish.partition { isFreshWater(it) }
- Kotlin ha molte funzioni utili per
List
, comereversed()
,contains()
esubList()
. - È possibile utilizzare un
HashMap
per mappare le chiavi ai valori. Ad esempio:val cures = hashMapOf("white spots" to "Ich", "red sores" to "hole disease")
- Dichiara le costanti del tempo di compilazione utilizzando la parola chiave
const
. Puoi posizionarle al livello più alto, organizzarle in un oggetto singleton o posizionarle in un oggetto companion. - Un oggetto companion è un oggetto singleton all'interno di una definizione di classe, definito con la parola chiave
companion
. - Le proprietà e le funzioni delle estensioni possono aggiungere funzionalità a una classe. Ad esempio:
fun String.hasSpaces() = find { it == ' ' } != null
- Un destinatario nullo consente di creare estensioni in una classe che può essere
null
. L'operatore?.
può essere associato aapply
per controllarenull
prima di eseguire il codice. Ad esempio:this?.apply { println("removing $this") }
Documentazione di Kotlin
Se vuoi saperne di più su qualsiasi argomento del corso o se ti blocchi, https://kotlinlang.org è il punto di partenza migliore.
Tutorial su Kotlin
Il sito web https://try.kotlinlang.org include tutorial avanzati chiamati Kotlin Koans, un interprete basato sul Web, e una serie completa di documentazione di riferimento con esempi.
Corso Udacity
Per visualizzare il corso Udacity su questo argomento, consulta il Kotlin Bootcamp for Programrs.
IDA IntelliJ
La documentazione relativa a IntelliJ IDEA è disponibile sul sito web di JetBrains.
In questa sezione sono elencati i possibili compiti per gli studenti che lavorano attraverso questo codelab nell'ambito di un corso tenuto da un insegnante. Spetta all'insegnante fare quanto segue:
- Assegna i compiti, se necessario.
- Comunica agli studenti come inviare compiti.
- Valuta i compiti.
Gli insegnanti possono utilizzare i suggerimenti solo quanto e come vogliono e dovrebbero assegnare i compiti che ritengono appropriati.
Se stai lavorando da solo a questo codelab, puoi utilizzare questi compiti per mettere alla prova le tue conoscenze.
Rispondi a queste domande
Domanda 1
Quale dei seguenti elementi restituisce una copia di un elenco?
▢ add()
▢ remove()
▢ reversed()
▢ contains()
Domanda 2
Quale di queste funzioni di estensione su class AquariumPlant(val color: String, val size: Int, private val cost: Double, val leafy: Boolean)
restituirà un errore di compilazione?
▢ fun AquariumPlant.isRed() = color == "red"
▢ fun AquariumPlant.isBig() = size > 45
▢ fun AquariumPlant.isExpensive() = cost > 10.00
▢ fun AquariumPlant.isNotLeafy() = leafy == false
Domanda 3
Quale dei seguenti non è un luogo in cui puoi definire costanti con const val
?
▢ all'inizio del file
▢ nelle classi normali
▢ negli oggetti Singleton
▢ negli oggetti companion
Passa alla lezione successiva:
Per una panoramica del corso, inclusi i link ad altri codelab, vedi "Kotlin Bootcamp for Programs: Welcome to the Course."