Kotlin is een moderne programmeertaal die compileert met Java bytecode. Het is gratis en open source en belooft om het coderen voor Android nog leuker te maken.
In het vorige artikel leerde je over ranges en collecties in Kotlin. In deze zelfstudie blijven we de taal leren door te kijken hoe je code kunt organiseren met behulp van pakketten en vervolgens door te gaan naar een inleiding tot functies in Kotlin.
Als u bekend bent met Java, weet u dat Java pakketten gebruikt om gerelateerde klassen te groeperen; bijvoorbeeld de java.util
pakket heeft een aantal nuttige hulpprogramma klassen. Pakketten worden aangegeven met de pakket
zoekwoord en elk Kotlin-bestand met een pakket
verklaring aan het begin kan verklaringen van klassen, functies of interfaces bevatten.
Als we naar de onderstaande code kijken, hebben we een pakket gedeclareerd com.chikekotlin.projectx
de ... gebruiken pakket
trefwoord. We hebben ook een klas uitgeroepen Mijn klas
(we bespreken klassen in Kotlin in toekomstige berichten) in dit pakket.
pakket com.chikekotlin.projectx class MyClass
Nu, de volledig gekwalificeerde naam voor de klas Mijn klas
is com.chikekotlin.projectx.MyClass
.
package com.chikekotlin.projectx fun saySomething (): String return "Hoe ver?"
In de bovenstaande code hebben we een functie op het hoogste niveau gemaakt (we komen daar binnenkort op terug). Dus vergelijkbaar met Mijn klas
, de volledig gekwalificeerde naam voor de functie zeg iets()
is com.chikekotlin.projectx.saySomething
.
In Kotlin gebruiken we de importeren
verklaring om de compiler in staat te stellen de klassen, functies, interfaces of objecten die moeten worden geïmporteerd te lokaliseren. In Java daarentegen kunnen we niet rechtstreeks klassen of interfaces van functies of methoden importeren.
We gebruiken importeren
om toegang te krijgen tot een functie, interface, klasse of object buiten het pakket waar het werd verklaard.
import com.chikekotlin.projectx.saySomething fun main (args: Array) saySomething () // zal afdrukken "Hoe ver?"
In het bovenstaande codefragment hebben we de functie geïmporteerd zeg iets()
uit een ander pakket en vervolgens hebben we die functie uitgevoerd.
Kotlin ondersteunt ook invoer met jokertekens met behulp van de *
operator. Hiermee importeert u alle klassen, interfaces en functies die in het pakket in één keer zijn gedeclareerd. Dit wordt echter niet aanbevolen - het is meestal beter om uw import expliciet te maken.
import com.chikekotlin.projectx. *
Als u bibliotheken hebt met klassen of functienamen die tegenstrijdig zijn (ze verklaren bijvoorbeeld elk een functie met dezelfde naam), kunt u de zoals
sleutelwoord om die geïmporteerde entiteit een tijdelijke naam te geven.
import com.chikekotlin.projectx.saySomething import com.chikekotlin.projecty.saySomething as projectYSaySomething fun main (args: Array) projectYSaySomething ()
Merk op dat de tijdelijke naam alleen wordt gebruikt binnen het bestand waar het is toegewezen.
Een functie groepeert een reeks codeverklaringen die een taak uitvoeren. De details van de implementatie van de functie zijn verborgen voor de beller.
In Kotlin worden functies gedefinieerd met behulp van de pret
sleutelwoord, zoals getoond in het volgende voorbeeld:
fun hallo (naam: String): String return "Hallo $ naam" val message = hallo ("Chike") print (bericht) // zal "Hallo Chike" afdrukken
In de bovenstaande code hebben we een eenvoudige functie gedefinieerd Hallo()
met een enkele parameter naam
van type Draad
. Deze functie retourneert een Draad
type. Het formaat van de parameterdefinitie voor functies is naam: type
, bv. leeftijd: Int
, prijs: dubbel
, student: StudentClass
.
fun hello (name: String): Unit print ("Hello $ name") hallo ("Chike") // zal "Hallo Chike" afdrukken
De bovenstaande functie is vergelijkbaar met de vorige, maar merk op dat deze een retourneringstype heeft Eenheid
. Omdat deze functie ons geen significante waarde oplevert - het drukt gewoon een bericht af - is het retourneringstype dat is Eenheid
standaard. Eenheid
is een Kotlin-object (we bespreken Kotlin-objecten in latere berichten) die vergelijkbaar zijn met de leegte
typen in Java en C.
public object Unit overschrijf plezier toString () = "kotlin.Unit"
Merk op dat als u niet expliciet verklaart dat het retourneringstype is Eenheid
, het type wordt afgeleid door de compiler.
leuk hallo (naam: String) // zal nog steeds afdrukken compileren ("Hallo $ naam")
Functies met één regel of één regel zijn functies die slechts één uitdrukkingen zijn. In deze functie verwijderen we de beugel en gebruiken we de =
symbool voor de uitdrukking. Met andere woorden, we verwijderen het functieblok.
fun calCircumference (radius: Double): Double return (2 * Math.PI) * radius
De bovenstaande functie kan worden ingekort tot een enkele regel:
fun calCircumference (radius: Double) = (2 * Math.PI) * radius
Als u naar de bijgewerkte functie hierboven kijkt, ziet u dat we onze code beknopter hebben gemaakt door de accolades te verwijderen , de
terugkeer
zoekwoord en ook het retourtype (dat wordt afgeleid door de compiler).
U kunt het retourneringstype desgewenst nog explicieter opnemen.
fun calCircumference (radius: Double): Double = (2 * Math.PI) * radius
Benoemde parameters staan meer leesbare functies toe door de parameters te noemen die worden doorgegeven aan een functie bij het aanroepen.
In het volgende voorbeeld hebben we een functie gemaakt die mijn volledige naam afdrukt.
fun sayMyFullName (firstName: String, lastName: String, middleName: String): Unit print ("Mijn volledige naam is $ firstName $ middleName $ lastName");
Om de bovenstaande functie uit te voeren, zouden we het zo noemen:
sayMyFullName ("Chike", "Nnamdi", "Mgbemena")
Kijkend naar de functie-oproep hierboven, weten we niet welke Draad
type-argumenten komen overeen met welke functieparameters (hoewel sommige IDE's zoals IntelliJ IDEA ons kunnen helpen). Gebruikers van de functie zullen in de functiekenteken (of de broncode) of documentatie moeten kijken om te weten waar elke parameter mee correspondeert.
sayMyFullName (firstName = "Chike", middleName = "Nnamdi", lastName = "Mgbemena")
In de tweede functieoproep hierboven hebben we de parameternamen vóór de argumentwaarden opgegeven. U kunt zien dat deze functieaanroep duidelijker en leesbaarder is dan de vorige. Deze manier van aanroepen van functies vermindert de kans op fouten die kunnen optreden wanneer fouten van hetzelfde type per ongeluk worden geruild.
De beller kan ook de volgorde van de parameters wijzigen met behulp van benoemde parameters. Bijvoorbeeld:
sayMyFullName (lastName = "Mgbemena", middleName = "Nnamdi", firstName = "Chike") // zal nog steeds compileren
In de bovenstaande code hebben we de argumentpositie van de. Geruild Voornaam
met de achternaam
. De argumentvolgorde doet er niet toe met benoemde parameters, omdat de compiler elk van deze toewijst aan de juiste functieparameter.
In Kotlin kunnen we een standaardfunctie voor elk van zijn parameters opgeven. Deze standaardwaarden worden gebruikt als er niets is toegewezen aan de argumenten tijdens de functieaanroep. Om dit in Java te doen, zouden we verschillende overbelaste methoden moeten creëren.
Hier, in onze calCircumference ()
methode, hebben we de methode aangepast door een standaardwaarde toe te voegen voor de pi
parameter-Math.PI
, een constante van de java.lang.Math
pakket.
fun calCircumference (radius: Double, pi: Double = Math.PI): Double = (2 * pi) * radius
Wanneer we deze functie aanroepen, kunnen we onze geschatte waarde doorgeven pi
of gebruik de standaardinstelling.
print (calCircumference (24.0)) // gebruikte standaardwaarde voor PI en afdrukken 150.79644737231007 print (calCircumference (24.0, 3.14)) // doorgegeven waarde voor PI en afdrukken 150.72
Laten we nog een voorbeeld bekijken.
fun printName (firstName: String, middleName: String = "N / A", lastName: String) println ("voornaam: $ firstName - middle name: $ middleName - achternaam: $ lastName")
In de volgende code hebben we geprobeerd de functie te gebruiken, maar deze compileert niet:
printName ("Chike", "Mgbemena") // zal niet compileren
In de bovenstaande functie-aanroep geef ik mijn voornaam en achternaam door aan de functie en hoop ik de standaardwaarde voor de middelste naam te gebruiken. Maar dit compileert niet omdat de compiler verward is. Het weet niet waar het argument "Mgbemena" voor is - is het voor de Midden-naam
of de achternaam
parameter?
Om dit probleem op te lossen, kunnen we benoemde parameters en standaardparameters combineren.
printName ("Chike", lastName = "Mgbemena") // zal nu compileren
Aangezien Java standaardparameterwaarden niet ondersteunt in methoden, moet u expliciet alle parameterwaarden opgeven wanneer u een Kotlin-functie vanuit Java belt. Maar Kotlin biedt ons de functionaliteit om het voor de Java-bellers gemakkelijker te maken door de Kotlin-functie te annoteren @JvmOverloads
. Deze annotatie geeft de Kotlin-compiler de opdracht om de Java-overbelaste functies voor ons te genereren.
In het volgende voorbeeld hebben we de annotatie van de calCirumference ()
functie met @JvmOverloads
.
@Jvm Overtreft leuke calCircumference (radius: Double, pi: Double = Math.PI): Double = (2 * pi) * radius
De volgende code is gegenereerd door de Kotlin-compiler, zodat Java-bellers vervolgens kunnen kiezen welke te bellen.
// Java double calCircumference (dubbele straal, dubbele pi); dubbele calCircumference (dubbele straal);
In de laatst gegenereerde Java-methode definitie, de pi
parameter is weggelaten. Dit betekent dat de methode de standaard gebruikt pi
waarde.
In Java kunnen we een methode maken om een onbepaald aantal argumenten te ontvangen door een ellips op te nemen (...
) na een type in de parameterlijst van de methode. Dit concept wordt ook ondersteund door Kotlin-functies met het gebruik van de vararg
modifier gevolgd door de parameternaam.
fun printInts (vararg ints: Int): Unit voor (n in ints) print ("$ n \ t") printInts (1, 2, 3, 4, 5, 6) // wordt afgedrukt 1 2 3 4 5 6
De vararg
Met modifier kunnen bellers een door komma's gescheiden lijst met argumenten doorgeven. Achter de schermen wordt deze lijst met argumenten in een array ingepakt.
Wanneer een functie meerdere parameters heeft, de vararg
parameter is meestal de laatste parameter. Het is ook mogelijk om parameters na de te hebben vararg
, maar u moet de benoemde parameters gebruiken om ze op te geven wanneer u de functie aanroept.
fun printNumbers (myDouble: Double, myFloat: Float, vararg ints: Int) println (myDouble) println (myFloat) for (n in ints) print ("$ n \ t") printNumbers (1.34, 4.4F, 2, 3, 4, 5, 6) // zal compileren
Bijvoorbeeld, in de bovenstaande code, de parameter met de vararg
modifier staat in de laatste positie in een lijst met meerdere parameters (dit is wat we gewoonlijk doen). Maar wat als we het niet in de laatste positie willen? In het volgende voorbeeld bevindt het zich in de tweede positie.
fun printNumbers (myDouble: Double, vararg ints: Int, myFloat: Float) println (myDouble) println (myFloat) for (n in ints) print ("$ n \ t") printNumbers (1.34, 2, 3 , 4, 5, 6, myFloat = 4.4F) // compileert printNumbers (1.34, ints = 2, 3, 4, 5, 6, myFloat = 4.4F) // compileert printNumbers niet (myDouble = 1.34, ints = 2, 3, 4, 5, 6, myFloat = 4.4F) // zal ook niet compileren
Zoals je kunt zien in de bijgewerkte code hierboven, hebben we benoemde argumenten op de laatste parameter gebruikt om dit op te lossen.
Laten we zeggen dat we een reeks gehele getallen aan ons willen doorgeven printNumbers ()
functie. De functie verwacht echter dat de waarden worden uitgerold in een lijst met parameters. Als u probeert de array rechtstreeks in te geven printNumbers ()
, je zult zien dat het niet compileert.
val intsArray: IntArray = intArrayOf (1, 3, 4, 5) printNumbers (1.34, intsArray, myFloat = 4.4F) // zal niet compileren
Om dit probleem op te lossen, moeten we de spread-operator gebruiken *
. Deze operator pakt de array uit en geeft vervolgens de afzonderlijke elementen als argumenten door aan de functie voor ons.
val intsArray: IntArray = intArrayOf (1, 3, 4, 5) printNumbers (1.34, * intsArray, myFloat = 4.4F) // wordt nu gecompileerd
Door de spread-operator in te voegen *
voor intsArray
in de argumentenlijst van de functie compileert en produceert de code hetzelfde resultaat alsof we de elementen van intsArray
als een door komma's gescheiden lijst met argumenten.
Soms willen we meerdere waarden van een functie retourneren. Een manier is om de Paar
typ in Kotlin om een te maken Paar
en stuur het dan terug. Deze Paar
structuur bevat twee waarden die later kunnen worden gebruikt. Dit Kotlin-type kan elk type accepteren dat je aan zijn constructeur levert. En, wat meer is, de twee typen hoeven niet eens hetzelfde te zijn.
fun getUserNameAndState (id: Int): Pairrequire (id> 0, "Fout: id is minder dan 0") val userNames: Map = mapOf (101 tot "Chike", 102 tot "Segun", 104 tot "Jane") val userStates: Map = mapOf (101 tot "Lagos", 102 tot "Imo", 104 tot "Enugu") val userName = userNames [id] val userState = userStates [id] return Pair (userName, userState)
In de bovenstaande functie hebben we een nieuwe gebouwd Paar
door de userName
en userState
variabelen als respectievelijk het eerste en het tweede argument aan de constructor en hebben dit vervolgens geretourneerd Paar
naar de beller.
Een ander ding om op te merken is dat we een functie gebruikten genaamd vereisen()
in de getUserNameAndState ()
functie. Deze hulpfunctie uit de standaardbibliotheek wordt gebruikt om onze functiemelders een voorwaarde te geven om te voldoen, of anders een IllegalArgumentException
zal worden gegooid (we bespreken uitzonderingen in Kotlin in een volgende post). Het optionele tweede argument voor vereisen()
is een letterlijke functie die een bericht retourneert dat moet worden weergegeven als de uitzondering wordt gegenereerd. Bijvoorbeeld het bellen van de getUserNameAndState ()
functie en passing -1
als argument om het te activeren:
Paar
val userNameAndStatePair: Pair= getUserNameAndState (101) println (userNameAndStatePair.first) // Chike println (userNameAndStatePair.second) // Lagos
In de bovenstaande code hebben we toegang gekregen tot de eerste en tweede waarden van de Paar
type met behulp van zijn eerste
en tweede
eigenschappen.
Er is echter een betere manier om dit te doen: destructurering.
val (naam, staat) = getUserNameAndState (101) println (naam) // Chike println (staat) // Lagos
Wat we hebben gedaan in de bijgewerkte code hierboven is om direct de eerste en tweede waarden van de geretourneerde toe te wijzen Paar
type naar de variabelen naam
en staat
respectievelijk. Deze functie wordt genoemd destructureringsverklaring.
Nu, wat als u drie waarden tegelijk wilt retourneren? Kotlin biedt ons een ander nuttig type genaamd Verdrievoudigen
.
fun getUserNameStateAndAge (id: Int): Triplerequire (id> 0, "id is minder dan 0") val userNames: Map = mapOf (101 tot "Chike", 102 tot "Segun", 104 tot "Jane") val userStates: Map = mapOf (101 to "Lagos", 102 to "Imo", 104 to "Enugu") val userName = userNames [id] val userState = userStates [id] val userAge = 6 return Triple (gebruikersnamen [id], userStates [id ], userAge) val (naam, staat, leeftijd) = getUserNameStateAndAge (101) println (naam) // Chike println (state) // Lagos println (leeftijd) // 6
Ik weet zeker dat sommigen van jullie zich afvragen wat je moet doen als je meer dan drie waarden wilt retourneren. Het antwoord daarvoor zal in een later stadium zijn, wanneer we de dataklassen van Kotlin bespreken.
In deze tutorial leer je over de pakketten en basisfuncties in de Kotlin-programmeertaal. In de volgende tutorial in de Kotlin From Scratch-serie leer je meer over functies in Kotlin. Tot ziens!
Voor meer informatie over de Kotlin-taal, raad ik aan de Kotlin-documentatie te bezoeken. Of bekijk enkele van onze andere Android-apps voor app-ontwikkeling hier op Envato Tuts+!