Kotlin fra scratch pakker og grunnleggende funksjoner

Kotlin er et moderne programmeringsspråk som kompilerer til Java bytecode. Det er gratis og åpen kildekode, og lover å gjøre koding for Android enda morsommere. 

I forrige artikkel lærte du om områder og samlinger i Kotlin. I denne opplæringen fortsetter vi å lære språket ved å se på hvordan du organiserer kode ved hjelp av pakker, og fortsett deretter med en introduksjon til funksjoner i Kotlin.

1. Pakker

Hvis du er kjent med Java, vet du at Java bruker pakker til å gruppere relaterte klasser; for eksempel, java.util pakken har en rekke nyttige verktøysklasser. Pakker er deklarert med pakke søkeord og enhver Kotlin-fil med en pakke erklæringen i begynnelsen kan inneholde erklæringer om klasser, funksjoner eller grensesnitt.

Erklæring

Ser på koden nedenfor, har vi erklært en pakke com.chikekotlin.projectx bruker pakke søkeord. Også, erklærte vi en klasse Klassen min (vi diskuterer klasser i Kotlin i fremtidige innlegg) i denne pakken.

pakke com.chikekotlin.projectx klasse MyClass

Nå, fullt kvalifisert navn for klassen Klassen min er com.chikekotlin.projectx.MyClass.

pakke com.chikekotlin.projectx fun saySomething (): String return "Hvor langt?" 

I koden ovenfor opprettet vi en toppnivå funksjon (vi kommer til det kort tid). Så på samme måte som Klassen min, Det fullt kvalifiserte navnet på funksjonen si noe() er com.chikekotlin.projectx.saySomething.

import

I Kotlin bruker vi importere erklæring for å gjøre det mulig for kompilatoren å finne klassene, funksjonene, grensesnittene eller objektene som skal importeres. I Java, derimot, kan vi ikke direkte importere funksjoner eller metoder-bare klasser eller grensesnitt. 

Vi bruker importere for å få tilgang til en funksjon, grensesnitt, klasse eller objekt utenfor pakken der den ble erklært. 

importer com.chikekotlin.projectx.saySomething fun main (args: Array) saySomething () // vil skrive ut "Hvor langt?" 

I kodestykket ovenfor importerte vi funksjonen si noe() fra en annen pakke, og da utførte vi den funksjonen.

Kotlin støtter også wildcard import ved hjelp av * operatør. Dette vil importere alle klassene, grensesnittene og funksjonene deklarert i pakken alt på en gang. Dette anbefales ikke, men det er vanligvis bedre å gjøre importen eksplisitt.

importer com.chikekotlin.projectx. *

Import Aliasing

Når du har biblioteker som har motstridende klasse- eller funksjonsnavn (for eksempel de erklærer hver en funksjon med samme navn), kan du bruke som søkeord for å gi den importerte enheten et midlertidig navn.

importer com.chikekotlin.projectx.saySomething import com.chikekotlin.projecty.saySomething like projectYSaySomething fun main (args: Array) projectYSaySomething ()

Merk at det midlertidige navnet bare brukes i filen der den ble tildelt.

2. Funksjoner

En funksjon grupperer sammen en rekke kodeuttalelser som utfører en oppgave. Detaljer om implementeringen av funksjonen er skjult fra den som ringer.

I Kotlin defineres funksjoner ved hjelp av moro søkeord, som vist i følgende eksempel:

morsom hei (navn: String): String return "Hei $ navn" val melding = hello ("Chike") print (melding) // vil skrive ut "Hello Chike"

I koden ovenfor definerte vi en enkel funksjon Hallo() med en enkelt parameter Navn av type string. Denne funksjonen returnerer a string type. Parameterdefinisjonsformatet for funksjoner er navn: type, f.eks. alder: Int, pris: Dobbeltrom, Student: StudentClass.

morsom hei (navn: String): Enhet print ("Hei $ navn") hallo ("Chike") // vil skrive ut "Hello Chike"

Funksjonen ovenfor er lik den forrige, men legg merke til at denne har en returtype av Enhet. Fordi denne funksjonen ikke returnerer noen vesentlig verdi for oss, skriver den bare ut en melding - dens returtype er Enhet som standard. Enhet er et Kotlin-objekt (vi diskuterer Kotlin-objekter i senere innlegg) som ligner på Tomrom typer i Java og C.

offentlige objekt Enhet overstyre moro toString () = "kotlin.Unit"

Vær oppmerksom på at hvis du ikke eksplisitt erklærer returtypen å være Enhet, typen er utledet av kompilatoren.

morsom hallo (navn: String) // vil fortsatt kompilere utskrift ("Hei $ navn")

Single-Line Funksjoner

Enkeltlinje- eller enlinjefunksjoner er funksjoner som bare er enkle uttrykk. I denne funksjonen slipper vi av bøylene og bruker = symbol før uttrykket. Med andre ord blir vi kvitt funksjonsblokken.

morsom calCircumference (radius: Double): Double return (2 * Math.PI) * radius

Funksjonen ovenfor kan forkortes til en enkelt linje:

morsom calCircumference (radius: Double) = (2 * Math.PI) * radius

Ser du på den oppdaterte funksjonen ovenfor, kan du se at vi har gjort vår kode mer konsis ved å fjerne de krøllete båndene , de komme tilbake søkeord, og også returtype (som er utledet av kompilatoren). 

Du kan fortsatt inkludere returtype for å være mer eksplisitt hvis du vil.

morsom calCircumference (radius: Double): Double = (2 * Math.PI) * radius

Navngitte parametere

Navngitte parametre tillater mer lesbare funksjoner ved å navngi parametrene som sendes til en funksjon når de kalles.

I det følgende eksempelet opprettet vi en funksjon som skriver ut mitt fulle navn.

morsomt sayMyFullName (firstName: String, LastName: String, middleName: String): Enhet print ("Mitt fulle navn er $ firstName $ middleName $ lastName"); 

For å utføre funksjonen ovenfor, ville vi bare kalle det slik:

sayMyFullName ("Chike", "Nnamdi", "Mgbemena")

Ser på funksjonsanropet ovenfor, vet vi ikke hvilken string type argumenter tilsvarer hvilke funksjonsparametere (selv om noen IDEer som IntelliJ IDEA kan hjelpe oss). Brukere av funksjonen må se på funksjons signaturen (eller kildekoden) eller dokumentasjonen for å vite hva hver parameter tilsvarer.

sayMyFullName (firstName = "Chike", middleName = "Nnamdi", lastName = "Mgbemena")

I det andre funksjonssamtalen ovenfor leverte vi parameternavnene før argumentverdiene. Du kan se at denne funksjonen er klarere og mer lesbar enn den forrige. Denne måten å ringe funksjoner bidrar til å redusere muligheten for feil som kan skje når argumenter av samme type byttes av en feil.

Den som ringer kan også endre rekkefølgen på parametrene ved å bruke navngitte parametere. For eksempel:

sayMyFullName (lastName = "Mgbemena", middleName = "Nnamdi", firstName = "Chike") // vil fortsatt kompilere

I koden ovenfor byttet vi argumentets posisjon av fornavn med etternavn. Argumentordelen spiller ingen rolle med navngitte parametre fordi kompilatoren vil kartlegge hver av dem til riktig funksjonsparameter.

Standardparametere

I Kotlin kan vi gi standardverdier for alle parametere. Disse standardverdiene brukes hvis ingenting tilordnes argumentene under funksjonssamtalen. For å gjøre dette i Java, må vi opprette forskjellige overbelastede metoder.

Her i vår calCircumference () metode, endret vi metoden ved å legge til en standardverdi for pi parameter-Math.PI, en konstant fra java.lang.Math pakke. 

morsom calCircumference (radius: Double, pi: Double = Math.PI): Dobbel = (2 * pi) * radius

Når vi kaller denne funksjonen, kan vi enten passere vår tilnærmet verdi for pi eller bruk standardinnstillingen. 

print (calCircumference (24.0)) // brukt standardverdi for PI og utskrifter 150.79644737231007 print (calCircumference (24.0, 3.14)) // bestått verdi for PI og utskrifter 150.72

La oss se et annet eksempel.

morsom utskriftName (firstName: String, middleName: String = "N / A", etternavn: String) println ("fornavn: $ firstName - middle name: $ middleName - etternavn: $ lastName")

I den følgende koden prøvde vi å ringe til funksjonen, men den vil ikke kompilere:

printName ("Chike", "Mgbemena") // vil ikke kompilere

I funksjonssamtalen ovenfor overfører jeg mitt fornavn og etternavn til funksjonen, og håper å bruke standardverdien for mellomnavnet. Men dette vil ikke kompilere fordi kompilatoren er forvirret. Det vet ikke hva argumentet "Mgbemena" er for-er det for mellomnavn eller etternavn parameter? 

For å løse dette problemet kan vi kombinere navngitte parametere og standardparametere. 

printName ("Chike", lastName = "Mgbemena") // vil nå kompilere

Java interoperabilitet

Gitt at Java ikke støtter standardparameterverdier i metoder, må du spesifisere alle parameterverdiene eksplisitt når du kaller en Kotlin-funksjon fra Java. Men Kotlin gir oss funksjonaliteten for å gjøre det enklere for Java-oppringere ved å annotere Kotlin-funksjonen med @JvmOverloads. Denne annotasjonen vil instruere Kotlin-kompilatoren for å generere Java overbelastede funksjoner for oss.

I følgende eksempel annoterte vi calCirumference () fungere med @JvmOverloads.

@JvmOverloads morsom calCircumference (radius: Double, pi: Double = Math.PI): Dobbel = (2 * pi) * radius

Følgende kode ble generert av Kotlin-kompilatoren, slik at Java-oppringere kan velge hvilken som skal ringe.

// Java dobbelt calCircumference (dobbel radius, dobbel pi); Dobbelkalibrering (dobbel radius);

I den sist genererte Java-metoden definisjonen, pi parameteren ble utelatt. Dette betyr at metoden vil bruke standardinnstillingen pi verdi.

Ubegrenset Argumenter

I Java kan vi lage en metode for å motta et uspesifisert antall argumenter ved å inkludere en ellipsis (... ) etter en type i metodeparameterlisten. Dette konseptet støttes også av Kotlin-funksjoner ved bruk av vararg modifikator fulgt av parameternavnet.

morsom utskriftInter (varargint: Int): Enhet for (n i ints) print ("$ n \ t") printInter (1, 2, 3, 4, 5, 6) // vil skrive ut 1 2 3 4 5 6

De vararg modifier gjør det mulig for innringere å passere i en kommaseparert liste over argumenter. Bak kulissene blir denne listen over argumenter pakket inn i en matrise. 

Når en funksjon har flere parametere, vil vararg parameter er vanligvis den siste. Det er også mulig å ha parametere etter vararg, men du må bruke navngitte parametere for å angi dem når du ringer til funksjonen. 

morsomme printNumbers (myDouble: Double, myFloat: Float, varargint: Int) println (myDouble) println (myFloat) for (n ints) print ("$ n \ t") printNumbers (1.34, 4.4F, 2, 3, 4, 5, 6) / / vil kompilere

For eksempel, i koden ovenfor, parameteren med vararg Modifier er i den siste posisjonen i en liste over flere parametere (dette er det vi vanligvis gjør). Men hva om vi ikke vil ha det i den siste stillingen? I det følgende eksemplet er det i den andre posisjonen.

morsomme printNumbers (myDouble: Double, varargint: Int, myFloat: Float) println (myDouble) println (myFloat) for (n i int) print ("$ n \ t") printNumbers (1.34, 2, 3 , 4, 5, 6, myFloat = 4,4F) // vil kompilere printNumbers (1,34, ints = 2, 3, 4, 5, 6, myFloat = 4,4F) // vil ikke kompilere printNumbers (myDouble = 1.34, ints = 2, 3, 4, 5, 6, myFloat = 4,4F) // vil heller ikke kompilere

Som du kan observere i den oppdaterte koden ovenfor, brukte vi navngitte argumenter på den siste parameteren for å løse dette.

Spredningsoperatør

La oss si at vi ønsker å sende en rekke heltal til vår printNumbers () funksjon. Funksjonen forventer at verdiene skal rulles inn i en liste over parametere, skjønt. Hvis du prøver å overføre matrisen direkte inn printNumbers (), du ser at den ikke vil kompilere. 

val intsArray: IntArray = intArrayOf (1, 3, 4, 5) printNumbers (1.34, intsArray, myFloat = 4.4F) // vil ikke kompilere

For å løse dette problemet må vi bruke spredningsoperatøren *. Denne operatøren pakker ut arrayet og sender deretter de enkelte elementene som argumenter til funksjonen for oss. 

val intsArray: IntArray = intArrayOf (1, 3, 4, 5) printNumbers (1.34, * intsArray, myFloat = 4.4F) // vil nå kompilere

Ved å sette inn spredningsoperatøren * foran intsArray Koden i funksjonens argumentliste samler nå og gir samme resultat som om vi hadde bestått elementene i intsArray som en kommaseparert liste over argumenter. 

Returner flere verdier

Noen ganger ønsker vi å returnere flere verdier fra en funksjon. En måte er å bruke Par skriv inn Kotlin for å lage en Par og deretter returnere den. Dette Par strukturen omslutter to verdier som senere kan åpnes. Denne typen Kotlin kan akseptere alle typer du leverer sin konstruktør. Og, de to typene trenger ikke engang å være det samme. 

morsom getUserNameAndState (id: Int): Par krever (id> 0, "Feil: id er mindre enn 0") val userNames: Map = mapOf (101 til "Chike", 102 til "Segun", 104 til "Jane") val userStates: Map = mapOf (101 til "Lagos", 102 til "Imo", 104 til "Enugu") val userName = userNames [id] val userState = userStates [id] returnere Par (userName, userState)

I funksjonen ovenfor konstruerte vi en ny Par ved å passere username og userState variabler som henholdsvis den første og andre argumenter til konstruktøren, og returnerte den deretter Par til den som ringer.

En annen ting å merke seg er at vi brukte en funksjon som heter kreve () i getUserNameAndState () funksjon. Denne hjelpefunksjonen fra standardbiblioteket brukes til å gi våre funksjonsoppringere en forutsetning for å møte, ellers en IllegalArgumentException vil bli kastet (vi diskuterer unntak i Kotlin i et fremtidig innlegg). Det valgfrie andre argumentet til kreve () er en funksjon bokstavelig returnerer en melding som skal vises hvis unntaket kastes. For eksempel, ringer til getUserNameAndState () funksjon og passering -1 som et argument for det vil utløse:

 

Henter data fra Par

val userNameAndStatePair: Par = getUserNameAndState (101) println (userNameAndStatePair.first) // Chike println (userNameAndStatePair.second) // Lagos

I koden ovenfor har vi tilgang til første og andre verdier fra Par skriv ved å bruke dens først og sekund eiendommer.

Det er imidlertid en bedre måte å gjøre dette på: destrukturering.

val (navn, tilstand) = getUserNameAndState (101) println (navn) // Chike println (state) // Lagos

Det vi har gjort i den oppdaterte koden ovenfor, er å direkte tilordne den første og andre verdien av den returnerte Par skriv til variablene Navn og stat henholdsvis. Denne funksjonen kalles destruktivdeklarasjon.

Triple Return Verdier og utover

Nå, hva om du vil returnere tre verdier samtidig? Kotlin gir oss en annen nyttig type som kalles Triple.

morsom getUserNameStateAndAge (id: Int): Triple krever (id> 0, "id er mindre enn 0") val userNames: Map = mapOf (101 til "Chike", 102 til "Segun", 104 til "Jane") val userStates: Map = mapOf (101 til "Lagos", 102 til "Imo", 104 til "Enugu") val userName = userNames [id] val userState = userStates [id] val userAge = 6 retur Triple (userNames [id], userStates [id ], userAge) val (navn, tilstand, alder) = getUserNameStateAndAge (101) println (navn) // Chike println (state) // Lagos println (alder) // 6

Jeg er sikker på at noen av dere lurer på hva de skal gjøre hvis du vil returnere mer enn tre verdier. Svaret på det kommer til å ligge senere, når vi diskuterer Kotlins dataklasser.

Konklusjon

I denne opplæringen lærte du om pakker og grunnleggende funksjoner i Kotlins programmeringsspråk. I neste opplæring i Kotlin From Scratch-serien lærer du mer om funksjoner i Kotlin. Ser deg snart!

For å lære mer om Kotlin-språket, anbefaler jeg at du besøker Kotlin-dokumentasjonen. Eller sjekk ut noen av våre andre Android-apputviklingsposter her på Envato Tuts+!