Kotlin este un limbaj de programare modern care se compilează la Java bytecode. Este gratuit și open source, și promite să facă codificarea pentru Android chiar mai distractiv.
În articolul precedent, ați aflat despre pachete și funcții de bază în Kotlin. Funcțiile se află în centrul orașului Kotlin, astfel că în acest post ne vom uita mai atent. Vom explora următoarele funcții în Kotlin:
Veți fi uimiți de toate lucrurile minunate pe care le puteți face cu funcțiile din Kotlin!
Funcțiile de nivel superior sunt funcții în interiorul unui pachet Kotlin care sunt definite în afara oricărei clase, obiecte sau interfețe. Aceasta înseamnă că acestea sunt funcții pe care le apelați direct, fără a fi nevoie să creați obiecte sau să apelați nici o clasă.
Dacă sunteți un coder Java, știți că, în mod obișnuit, vom crea metode statice de utilitate în clasele de ajutor. Aceste clase de ajutoare nu fac nimic - nu au metode de stat sau instanță și acționează doar ca un container pentru metodele statice. Un exemplu tipic este Colecții
clasa în java.util
pachetul și metodele sale statice.
Funcțiile de nivel superior din Kotlin pot fi folosite ca înlocuitori pentru metodele de utilitate statică din clasele de ajutor pe care le codificăm în Java. Să ne uităm la definirea unei funcții de nivel superior în Kotlin.
pachet com.chikekotlin.projectx.utils distracție checkUserStatus (): String return "online"
În codul de mai sus, am definit un pachet com.chikekotlin.projectx.utils
în interiorul unui fișier numit UserUtils.kt și, de asemenea, a definit o funcție de utilitate de nivel superior numită checkUserStatus ()
în interiorul aceluiași pachet și fișier. Din fericire, această funcție foarte simplă returnează șirul "on-line".
Următorul lucru pe care îl vom face este să utilizați această funcție utilitar într-un alt pachet sau fișier.
pachet com.chikekotlin.projectx.users import com.chikekotlin.projectx.utils.checkUserStatus dacă (checkUserStatus () == "online") // face ceva
În codul precedent, am importat funcția într-un alt pachet și apoi l-am executat! După cum puteți vedea, nu este necesar să creați un obiect sau să faceți referire la o clasă pentru a apela această funcție.
Dat fiind că Java nu suportă funcții de nivel superior, compilatorul Kotlin din spatele scenei va crea o clasă Java, iar funcțiile individuale de nivel superior vor fi convertite în metode statice. În cazul nostru, clasa Java a fost generată UserUtilsKt
cu o metodă statică checkUserStatus ()
.
/ * Java * / pachet com.chikekotlin.projectx.utils clasă publică UserUtilsKt public static String checkUserStatus () return "online";
Acest lucru înseamnă că apelanții Java pot apela pur și simplu metoda prin referirea la clasa generată, la fel ca pentru orice altă metodă statică.
/ * Java * / import com.chikekotlin.projectx.utils.UserUtilsKt ... UserUtilsKt.checkUserStatus ()
Rețineți că putem schimba numele de clasă Java pe care compilatorul Kotlin îl generează utilizând @JvmName
adnotare.
@file: pachetul JvmName ("UserUtils") com.chikekotlin.projectx.utils fun checkUserStatus (): String return "online"
În codul de mai sus, am aplicat @JvmName
adnotare și a specificat numele unei clase UserUtils
pentru fișierul generat. Rețineți, de asemenea, că această adnotare este plasată la începutul fișierului Kotlin, înainte de definirea pachetului.
Se poate face referire din Java astfel:
/ * Java * / import com.chikekotlin.projectx.utils.UserUtils ... UserUtils.checkUserStatus ()
Expresiile Lambda (sau literali de funcții) nu sunt, de asemenea, legate de nici o entitate, cum ar fi o clasă, un obiect sau o interfață. Ele pot fi transmise ca argumente altor funcții numite funcții de ordin superior (vom discuta mai multe despre acestea în următoarea postare). O expresie lambda reprezintă doar blocul unei funcții, iar utilizarea acestora reduce zgomotul din codul nostru.
Dacă sunteți coder Java, știți că Java 8 și mai sus oferă suport pentru expresiile lambda. Pentru a folosi expresiile lambda într-un proiect care acceptă versiuni Java mai vechi, cum ar fi Java 7, 6 sau 5, putem folosi popularul bibliotecă Retrolambda.
Unul dintre lucrurile minunate despre Kotlin este că expresiile lambda sunt susținute din cutie. Deoarece lambda nu este acceptată în Java 6 sau 7, pentru Kotlin să interacționeze cu ea, Kotlin creează o clasă anonimă Java în spatele scenei. Dar rețineți că crearea unei expresii lambda în Kotlin este destul de diferită decât în Java.
Iată caracteristicile unei expresii lambda în Kotlin:
.distracţie
cuvinte cheie. ()
. Și mai mult, putem atribui o expresie lambda unei variabile și apoi execută-o.
Să vedem acum câteva exemple de expresii lambda. În codul de mai jos, am creat o expresie lambda fără parametri și i-am atribuit o variabilă mesaj
. Apoi am executat expresia lambda sunând mesaj()
.
val mesaj = println ("Hei, Kotlin este foarte cool!") mesaj () // "Hei, Kotlin este foarte cool!"
Să vedem, de asemenea, cum să includem parametrii într-o expresie lambda.
val mesaj = myString: String -> println (myString) mesaj ("Îmi place Kotlin") // "Îmi place Kotlin" ("Cât de departe?") // "Cât de departe?"
În codul de mai sus, am creat o expresie lambda cu parametrul myString
, împreună cu tipul de parametru Şir
. După cum puteți vedea, în fața tipului de parametru, există o săgeată: aceasta se referă la corpul lambda. Cu alte cuvinte, această săgeată separă lista de parametri de corpul lambda. Pentru a face mai concis, putem ignora complet tipul de parametru (deja dedus de compilator).
val mesaj = myString -> println (myString) // va mai fi compilat
Pentru a avea mai mulți parametri, le separăm doar cu o virgulă. Și rețineți că nu împachetăm lista de parametri în paranteze ca în Java.
val addNumbers = număr1: Int, numărul2: Int -> println ("Adăugarea $ number1 și $ number2") val result = number1 + number2 println ("
Totuși, rețineți că dacă tipurile de parametru nu pot fi deduse, ele trebuie specificate explicit (ca în acest exemplu), altfel codul nu va fi compilat.
Adăugarea rezultatelor 1 și 3 Rezultatul este 4
Putem transmite expresii lambda ca parametri pentru funcții: acestea se numesc "funcții de ordin superior", deoarece sunt funcții de funcții. Aceste tipuri de funcții pot accepta o funcție lambda sau o funcție anonimă ca parametru: de exemplu, ultimul()
funcție de colectare.
În codul de mai jos, am trecut într-o expresie lambda la ultimul()
funcţie. (Dacă doriți o actualizare a colecțiilor din Kotlin, vizitați cel de-al treilea tutorial din această serie) După cum spune numele, acesta returnează ultimul element din listă. ultimul()
acceptă o expresie lambda ca parametru, iar această expresie, la rândul său, ia un argument de tip Şir
. Organismul său funcțional servește ca predicat pentru a căuta într-un subset de elemente din colecție. Aceasta înseamnă că expresia lambda va decide care elemente ale colecției vor fi luate în considerare atunci când o caută pe ultima.
val stringList: Listă= listOf ("in", "the", "club") print (stringList.last ()) // va imprima "club" print (stringList.last (s: String -> s.length == 3) ) // va imprima "
Să vedem cum să facem ca ultimul rând de cod de mai sus să fie mai ușor de citit.
stringList.last s: String -> s.length == 3 // va compila si imprima si "the"
Compilatorul Kotlin ne permite să eliminăm parantezele funcției dacă ultimul argument din funcție este o expresie lambda. După cum puteți observa în codul de mai sus, ni sa permis să facem acest lucru, deoarece ultimul și singurul argument a fost transmis ultimul()
este o expresie lambda.
Mai mult, putem elimina tipul de parametru mai concis.
stringList.last s -> s.length == 3 // va compila, de asemenea, imprimarea "the"
Nu este necesar să specificăm explicit tipul de parametru, deoarece tipul de parametru este întotdeauna același cu tipul elementului de colecție. În codul de mai sus, sunăm ultimul
pe o colecție de listă Şir
obiecte, astfel încât compilatorul Kotlin este suficient de inteligent pentru a ști că parametrul va fi de asemenea a Şir
tip.
aceasta
Numele ArgumentuluiPutem chiar să simplificăm din nou expresia lambda înlocuind argumentul expresiei lambda cu numele argumentului implicit generat automat aceasta
.
stringList.last it.length == 3
aceasta
numele argumentului a fost generat automat deoarece ultimul
poate accepta o expresie lambda sau o funcție anonimă (vom ajunge la asta în curând) cu un singur argument și tipul său poate fi dedus de compilator.
Să începem cu un exemplu. În codul de mai jos, trecem la o expresie lambda pentru fiecare()
funcția invocată pe intList
Colectie. Această funcție va trece prin colecție și va executa lambda pe fiecare element din listă. Dacă un element este divizibil cu 2, acesta se va opri și va reveni din lambda.
Funcția în jurul Funcției () val intList = listOf (1, 2, 3, 4, 5) intList.forEach if (it% 2 == 0) return println ("End ofroundFunction ) // nu s-a intamplat nimic
Este posibil ca rularea codului de mai sus să nu fi dat rezultatul pe care l-ați fi așteptat. Acest lucru se datorează faptului că declarația de returnare nu se va întoarce din lambda, ci din funcția care conține surroundingFunction ()
! Aceasta înseamnă că ultima instrucțiune de cod din surroundingFunction ()
nu va executa.
// ... println ("End ofFunction ()") // Aceasta nu va executa // ...
Pentru a rezolva această problemă, trebuie să-i spunem în mod explicit la ce funcție să revenim folosind o etichetă sau o etichetă de nume.
distracție înconjurătoareFunction () val intList = listOf (1, 2, 3, 4, 5) intList.forEach if (it% 2 == 0) return @ forEach println / Acum, se va executa înconjurătoareFunction () // print "End ofroundFunction ()"
În codul actualizat de mai sus, am specificat eticheta implicită @pentru fiecare
imediat după întoarcere
cuvinte cheie din interiorul lambda. Acum am instruit compilatorul să se întoarcă de la lambda în locul funcției care conține surroundingFunction ()
. Acum ultima declarație din surroundingFunction ()
va executa.
Rețineți că putem, de asemenea, să definim eticheta proprie sau eticheta de nume.
// ... intList.forEach myLabel @ if (it% 2 == 0) retur @ myLabel // ...
În codul de mai sus, am definit eticheta personalizată numită mylabel @
și apoi a specificat-o pentru întoarcere
cuvinte cheie. @pentru fiecare
eticheta generată de compilator pentru pentru fiecare
funcția nu mai este disponibilă deoarece am definit propriul nostru.
Cu toate acestea, veți vedea în curând cum poate fi rezolvată această problemă de returnare locală fără etichete atunci când discutăm în scurt timp despre funcțiile anonime din Kotlin.
Acest tip de funcție este definit într-o clasă, obiect sau interfață. Utilizarea funcțiilor membrilor ne ajută să ne modularizăm în continuare programele. Să vedem acum cum să creăm o funcție membră.
clasa Circle fun calculateArea (raza: Dubla): Dubla necesita (raza> 0, "Radiusul trebuie sa fie mai mare de 0") returnare Math.PI * Math.pow (radius, 2.0)
Acest fragment de cod afișează o clasă Cerc
(vom discuta despre cursurile Kotlin în posturi ulterioare) care are o funcție membră calculateArea ()
. Această funcție are un parametru rază
pentru a calcula aria unui cerc.
Pentru a invoca o funcție de membru, vom folosi numele instanței de clasă sau obiect cu un punct, urmat de numele funcției, trecând orice argument dacă este necesar.
val circle = cerc () print (circle.calculateArea (4.5)) // va imprima "63.61725123519331"
O funcție anonimă este un alt mod de a defini un bloc de cod care poate fi transmis unei funcții. Nu este obligat la nici un identificator. Iată caracteristicile unei funcții anonime în Kotlin:
distracţie
cuvinte cheieval stringList: Listă= listOf ("in", "cel", "clubul") print (stringList.last it.length == 3) // va imprima "
Pentru că am trecut o lambda la ultimul()
funcția de mai sus, nu putem fi explicit despre tipul de returnare. Pentru a fi explicit despre tipul de returnare, trebuie să folosim o funcție anonimă.
val strLenThree = stringList.last (fun (șir): Boolean return string.length == 3) print (strLenThree) // va imprima "
În codul de mai sus, am înlocuit expresia lambda cu o funcție anonimă, deoarece vrem să fim explicit despre tipul de returnare.
Spre sfârșitul secțiunii lambda din acest tutorial am folosit o etichetă pentru a specifica care dintre funcții să se întoarcă. Folosind o funcție anonimă în loc de o lambda înăuntru pentru fiecare()
funcția rezolvă această problemă mai simplu. Expresia de întoarcere revine din funcția anonimă și nu din cea din jur, ceea ce este în cazul nostru surroundingFunction ()
.
distracție înconjurătoareFunction () val intList = listOf (1, 2, 3, 4, 5) intList.forEach (distracție (număr) if (număr% 2 == 0) return println ) ") // declarație executată înconjurătoareFunction () // va imprima" End ofroundFunction () "
Pentru a lua mai departe modularizarea programelor, Kotlin ne oferă funcții locale - cunoscute și ca funcții imbricate. O funcție locală este o funcție declarată în interiorul unei alte funcții.
distracție printCircumferenceAndArea (rază: dublă): unitate fun calCircumferință (rază: dublă): dublă = (2 * Math.PI) * radius circum circumference = "% .2f" .format (calCircumference (radius) ("Raza de raza") este circumferinta $ si circumferinta este suprafața $ ") printCircumferenceAndArea (3.0) // Circumferința circulară de 3.0 rază este 18.85 și aria este 28.27
După cum puteți observa în fragmentul de cod de mai sus, avem două funcții cu o singură linie: calCircumference ()
și calArea ()
imbricat în interior printCircumferenceAndAread ()
funcţie. Funcțiile imbricate pot fi apelate numai din interiorul funcției de închidere și nu din exterior. Din nou, utilizarea funcțiilor imbricate face ca programul nostru să fie mai modular și mai ordonat.
Putem face funcțiile noastre locale mai concise prin faptul că nu le transmitem în mod explicit parametrii. Acest lucru este posibil deoarece funcțiile locale au acces la toți parametrii și variabilele funcției de închidere. Să vedem asta acum în acțiune:
distracție printCircumferenceAndArea (rază: dublă): Unitate fun calCircumference (): Double = (2 * Math.PI) * radius val circumference = "% .2f" .format (calCircumference .PI) * Math.pow (raza, 2.0) val area = "% .2f" .format (calArea ()) // ...
După cum puteți vedea, acest cod actualizat arată mai ușor de citit și reduce zgomotul pe care l-am avut înainte. Deși funcția de închidere din acest exemplu este mică, într-o funcție de închidere mai mare, care poate fi împărțită în funcții imbricate mai mici, această caracteristică poate fi cu adevărat utilă.
infix
notația ne permite să apelam cu ușurință o funcție membră cu un argument sau o funcție de extensie. În afară de o funcție care este un argument, trebuie să definiți funcția folosind infix
modificator. Pentru a crea o funcție infix, sunt implicați doi parametri. Primul parametru este obiectul țintă, în timp ce al doilea parametru este doar un singur parametru trecut la funcție.
Să ne uităm la modul de creare a unei funcții infix într-o clasă. În exemplul de cod de mai jos, am creat o Student
clasa cu un mutable kotlinScore
câmp instanță. Am creat o funcție infix folosind infix
modificator înainte de distracţie
cuvinte cheie. După cum puteți vedea mai jos, am creat o funcție infix addKotlinScore ()
care ia un scor și adaugă la kotlinScore
instanță.
clasa Student var kotlinScore = 0.0 infix distracție addKotlinScore (scor: dublu): Unit this.kotlinScore = kotlinScore + scor
Să vedem, de asemenea, cum să invocăm funcția infix pe care am creat-o. Pentru a apela o funcție infix în Kotlin, nu este nevoie să folosim notația punctului și nu trebuie să înfășurăm parametrul cu paranteze.
val student = Student () student addKotlinScore 95.00 print (student.kotlinScore) // va imprima "95.0"
În codul de mai sus, am numit funcția infix, obiectul țintă este student
, și dublu 95.00
este parametrul transmis funcției.
Folosind cu ușurință funcțiile infix, codul nostru poate fi mai expresiv și mai clar decât stilul normal. Acest lucru este foarte apreciat atunci când scriem teste unitate în Kotlin (vom discuta despre testarea în Kotlin într-un post viitor).
"Chike" ar trebui să înceapă Cu ("ch") MyList ar trebui să conțină (myElement) "Chike" ar trebui să aibăLength (5) myMap ar trebui să haveKey (myKey)
la
Funcția InfixÎn Kotlin, putem face crearea unui Pereche
exemplu mai succint prin utilizarea la
infix funcția în loc de Pereche
constructor. (În spatele scenelor, la
creează și o Pereche
exemplu). Rețineți că la
funcția este, de asemenea, o funcție de extindere (vom discuta mai multe despre acestea în următoarea postare).
public infix distracție A.to (că: B): Pereche = Pereche (asta, asta)
Să comparăm crearea a Pereche
exemplu folosind ambele la
infix funcția și direct folosind Pereche
constructor, care efectuează aceeași operațiune, și a vedea care este mai bine.
val nigeriaCallingCodePair = 234 la "Nigeria" val nigeriaCallingCodePair2 = Perechea (234, "Nigeria") // Același lucru de mai sus
După cum puteți vedea în codul de mai sus, folosind la
funcția infix este mai concisă decât utilizarea directă Pereche
constructor pentru a crea un Pereche
instanță. Amintiți-vă că folosind la
infix funcție, 234
este obiectul țintă și Şir
"Nigeria" este parametrul transmis funcției. Mai mult decât atât, rețineți că putem face acest lucru și pentru a crea o Pereche
tip:
val nigeriaCallingCodePair3 = 234.to ("Nigeria") // la fel ca folosind 234 la "Nigeria"
În postul Ranges and Collections, am creat o colecție de hărți în Kotlin, oferindu-i o listă de perechi - prima valoare fiind cheia, iar a doua valoare. Să comparăm, de asemenea, crearea unei hărți folosind ambele la
infix și funcția Pereche
constructor pentru a crea perechi individuale.
val callingCodesMap: Harta= mapOf (234 la "Nigeria", 1 la "SUA", 233 la "Ghana")
În codul de mai sus, am creat o listă separată prin virgulă Pereche
tipuri folosind la
infix funcția și le-a trecut la harta()
funcţie. De asemenea, putem crea aceeași hartă utilizând direct Pereche
constructor pentru fiecare pereche.
val apelareaCodesPairMap: Harta= mapOf (pereche (234, "Nigeria"), pereche (1, "SUA"), pereche (233, "Ghana"))
După cum puteți vedea din nou, lipirea cu la
infix funcția are mai puțin zgomot decât utilizarea Pereche
constructor.
În acest tutorial, ați aflat despre unele lucruri interesante pe care le puteți face cu funcțiile din Kotlin. Am acoperit:
Dar asta nu este tot! Mai sunt multe de învățat despre funcțiile din Kotlin. Deci, în postul următor, veți învăța câteva utilizări avansate ale funcțiilor, cum ar fi funcții de extensie, funcții de ordin superior și închideri. Ne vedem în curând!
Pentru a afla mai multe despre limba Kotlin, vă recomand să vizitați documentația Kotlin. Sau verificați câteva dintre celelalte postări pentru dezvoltarea aplicațiilor Android aici pe Envato Tuts+!