Kotlin from Scratch pakketten en basisfuncties

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.

1. Pakketten

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.

Verklaring

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.

invoer

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. *

Import Aliasing

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.

2. Functies

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 voor enkele regel

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

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.

Standaardparameters

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

Java-interoperabiliteit

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.

Onbeperkte argumenten

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.

Spread Operator

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. 

Retourneer meerdere waarden

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): Pair require (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:

 

Gegevens ophalen van 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.

Drievoudige retourwaarden en meer

Nu, wat als u drie waarden tegelijk wilt retourneren? Kotlin biedt ons een ander nuttig type genaamd Verdrievoudigen.

fun getUserNameStateAndAge (id: Int): Triple require (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.

Conclusie

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+!