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.
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.
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
.
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. *
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.
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")
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 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.
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
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.
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.
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.
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): Parkrever (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:
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.
Nå, hva om du vil returnere tre verdier samtidig? Kotlin gir oss en annen nyttig type som kalles Triple
.
morsom getUserNameStateAndAge (id: Int): Triplekrever (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.
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+!