15-bo‘lim
Lambda va qamrov funksiyalari
Lambda yozuvi, funksiya turlari, yuqori tartibli funksiyalar, funksiya havolalari va let, run, with, apply, also orasidagi farq.
Ushbu bo‘lim mundarijasi
Kotlin da funksiya - oddiy qiymat. Uni o'zgaruvchida saqlash, parametr sifatida uzatish va qaytarish mumkin.
Lambda #
fun main() {
val kvadrat = { x: Int -> x * x }
val qoshish = { a: Int, b: Int -> a + b }
val salom = { println("Salom!") }
println(kvadrat(9))
println(qoshish(15, 27))
salom()
}
81
42
Salom!
Shakli: { parametrlar -> tana }. Oxirgi ifoda qaytariladigan qiymat
bo'ladi - return yozilmaydi.
Funksiya turlari #
fun main() {
val kvadrat: (Int) -> Int = { it * it }
val qoshish: (Int, Int) -> Int = { a, b -> a + b }
val chiqar: (String) -> Unit = { println(">> $it") }
val tasodifiy: () -> Int = { 42 }
println(kvadrat(5))
println(qoshish(2, 3))
chiqar("matn")
println(tasodifiy())
}
25
5
>> matn
42
(Int, Int) -> Int - "ikkita Int oladi va Int qaytaradi". Tur
yozilgan bo'lsa, lambda ichida parametr turlarini takrorlash shart
emas.
Bitta parametr bo'lsa, unga it deb murojaat qilinadi.
Yuqori tartibli funksiyalar #
fun bajar(a: Int, b: Int, amal: (Int, Int) -> Int): Int = amal(a, b)
fun takrorla(marta: Int, ish: (Int) -> Unit) {
for (i in 1..marta) ish(i)
}
fun main() {
println(bajar(6, 7) { x, y -> x * y })
println(bajar(6, 7) { x, y -> x + y })
takrorla(3) { println("$it-qadam") }
}
42
13
1-qadam
2-qadam
3-qadam
Yuqorida bajar(6, 7) { x, y -> x * y } deb yozildi, bajar(6, 7, { ... })
emas.
Kotlin qoidasi: oxirgi parametr funksiya bo'lsa, lambda ni
qavsdan keyin yozish mumkin. Lambda yagona parametr bo'lsa, qavsni
butunlay tushirib qoldirish mumkin: takrorla { }.
Aynan shu qoida tufayli listOf(1,2,3).filter { it > 1 } shunday
tabiiy ko'rinadi - va o'z funksiyangizni ham shunday qilib yozishingiz
mumkin. Funksiya parametrini oxirgi o'ringa qo'ying.
Funksiya qaytarish #
fun kopaytiruvchi(son: Int): (Int) -> Int = { it * son }
fun tekshiruvchi(chegara: Int): (Int) -> Boolean = { it > chegara }
fun main() {
val ikkilantir = kopaytiruvchi(2)
val uchlantir = kopaytiruvchi(3)
println(ikkilantir(10))
println(uchlantir(10))
val kattami = tekshiruvchi(50)
println(listOf(20, 60, 45, 80).filter(kattami))
}
20
30
[60, 80]
kopaytiruvchi(2) yangi funksiya yasab beradi. Bu funksiya son
qiymatini eslab qoladi - bunga yopilma (closure) deyiladi.
Yopilma #
fun sanagichYasa(): () -> Int {
var soni = 0
return { soni++; soni }
}
fun main() {
val sana = sanagichYasa()
println(sana())
println(sana())
println(sana())
val boshqa = sanagichYasa()
println(boshqa())
}
1
2
3
1
soni o'zgaruvchisi funksiya tugagandan keyin ham yashab qoldi -
lambda uni ushlab turibdi. Har bir chaqiruv esa o'z nusxasini
oladi.
Java da lambda faqat final o'zgaruvchini ushlay oladi - uni
o'zgartirib bo'lmaydi.
Kotlin da esa var ni ham ushlash va o'zgartirish mumkin, yuqoridagi
misoldagidek. Bu qulayroq, lekin ehtiyot bo'ling: ko'p oqimli
dasturda bunday o'zgaruvchi muammo manbaiga aylanadi.
Funksiya havolalari #
fun juftmi(x: Int): Boolean = x % 2 == 0
fun main() {
val sonlar = listOf(1, 2, 3, 4, 5, 6)
println(sonlar.filter(::juftmi))
println(sonlar.filter { juftmi(it) })
val ismlar = listOf("malika", "aziza")
println(ismlar.map(String::uppercase))
println(ismlar.map(String::length))
val chiqar: (String) -> Unit = ::println
chiqar("havola orqali")
}
[2, 4, 6]
[2, 4, 6]
[MALIKA, AZIZA]
[6, 5]
havola orqali
::nom - mavjud funksiyaga havola. Tur::metod - o'sha turning
metodiga.
Oxirgi misolda tur aniq yozilgan: val chiqar: (String) -> Unit = ::println.
Usiz kompilyator xato beradi, chunki println ning o'nga yaqin
versiyasi bor - Int, Double, Any? va boshqalar uchun - va
qaysi birini olishni bilmaydi.
Qoida: funksiyaning bitta versiyasi bo'lsa, turni yozish shart emas; bir nechtasi bo'lsa - kutilayotgan turni ko'rsating.
Qamrov funksiyalari #
Kotlin da beshta maxsus funksiya bor. Ular obyekt ustida blok bajaradi va bir-biridan ikki narsa bilan farq qiladi: obyektga qanday murojaat qilinadi va nima qaytariladi.
| Funksiya | Obyekt | Qaytaradi |
|---|---|---|
let | it | Blok natijasi |
run | this | Blok natijasi |
with | this | Blok natijasi |
apply | this | Obyektning o'zi |
also | it | Obyektning o'zi |
let #
fun main() {
val ism: String? = "Malika"
ism?.let {
println("Uzunlik: ${it.length}")
println("Katta: ${it.uppercase()}")
}
val uzunlik = ism?.let { it.length * 2 } ?: 0
println(uzunlik)
val sonlar = listOf(1, 2, 3)
println(sonlar.map { it * 2 }.let { "Natija: $it" })
}
Uzunlik: 6
Katta: MALIKA
12
Natija: [2, 4, 6]
let - eng ko'p null tekshiruvi bilan ishlatiladi va zanjirning
oxirida natijani o'zgartirish uchun.
apply - sozlash uchun #
class Sozlama {
var til: String = "uz"
var mavzu: String = "yorug'"
var avtoSaqlash: Boolean = false
override fun toString() = "$til/$mavzu/$avtoSaqlash"
}
fun main() {
val s = Sozlama().apply {
til = "en"
mavzu = "tungi"
avtoSaqlash = true
}
println(s)
val royxat = mutableListOf<Int>().apply {
add(1)
add(2)
add(3)
}
println(royxat)
}
en/tungi/true
[1, 2, 3]
apply obyektni qaytaradi - shuning uchun yaratish va sozlashni
bitta ifodada qilish mumkin. Blok ichida this yozish shart emas.
also - yon ta'sir uchun #
fun main() {
val natija = listOf(3, 1, 2)
.also { println("Boshlang'ich: $it") }
.sorted()
.also { println("Saralangan: $it") }
.map { it * 10 }
.also { println("Ko'paytirilgan: $it") }
println("Yakuniy: $natija")
}
Boshlang'ich: [3, 1, 2]
Saralangan: [1, 2, 3]
Ko'paytirilgan: [10, 20, 30]
Yakuniy: [10, 20, 30]
also - zanjirni buzmasdan oraliq natijani ko'rish uchun ideal.
Xatoni topishda juda qulay.
run va with #
class Hisob(val egasi: String, val qoldiq: Int)
fun main() {
val h = Hisob("Husanboy", 500000)
val tavsif = h.run {
"$egasi: $qoldiq so'm"
}
println(tavsif)
val natija = with(h) {
val soliq = qoldiq / 100
"Soliq: $soliq"
}
println(natija)
val qiymat = run {
val a = 10
val b = 20
a + b
}
println(qiymat)
}
Husanboy: 500000 so'm
Soliq: 5000
30
run va with deyarli bir xil. Farq shaklda: h.run { } va
with(h) { }. Birinchisi null bilan ham ishlaydi (h?.run { }).
Qaysi birini tanlash #
Ikkita let ni ichma-ich yozsangiz, ikkala blokda ham it bo'ladi
va qaysi biri qaysi ekanini aytish qiyinlashadi.
Bunday holatda parametrga nom bering:
foydalanuvchi?.let { f ->
f.manzil?.let { m ->
println("${f.ism}: ${m.shahar}")
}
}
Yoki umuman qamrov funksiyasisiz, oddiy if bilan yozing - u
ko'pincha o'qishliroq bo'ladi.
inline haqida qisqacha #
inline fun olcha(nom: String, ish: () -> Unit) {
val boshi = System.nanoTime()
ish()
val vaqt = System.nanoTime() - boshi
println("$nom: ${vaqt > 0}")
}
fun main() {
olcha("sikl") {
var s = 0
for (i in 1..1000) s += i
println("Yig'indi: $s")
}
}
Yig'indi: 500500
sikl: true
inline - kompilyatorga "bu funksiyaning tanasini chaqirilgan joyga
ko'chirib qo'y" deydi. Shunda lambda uchun obyekt yaratilmaydi.
Standart kutubxonadagi filter, map, let - hammasi inline.
Shuning uchun ular sikl yozgan bilan bir xil tezlikda ishlaydi.
- Ikkita sonni ko'paytiradigan lambda yozing.
(Int, Int) -> Intturini aniq yozing.- Amalni parametr sifatida oladigan funksiya yarating.
- Lambda ni qavsdan tashqariga chiqarib yozing.
- Funksiya qaytaradigan funksiya yozing.
- Yopilma bilan sanagich yasang.
::nomhavolasinifilterda ishlating.applybilan obyekt yaratib sozlang.alsobilan zanjirdagi oraliq natijalarni chiqaring.let,run,applyfarqini bitta obyektda ko'rsating.
Xulosa #
- Lambda:
{ parametr -> tana }; oxirgi ifoda qaytariladi. - Funksiya turi:
(Int, Int) -> Int. - Oxirgi parametr lambda bo'lsa, uni qavsdan tashqarida yozish mumkin - o'z funksiyangizni ham shunday loyihalang.
- Yopilma: lambda tashqi o'zgaruvchini ushlab qoladi va Kotlin da
varni ham o'zgartira oladi. ::nomvaTur::metod- funksiya havolalari.applyvaalsoobyektni qaytaradi;let,run,withblok natijasini.let-nulluchun,apply- sozlash uchun,also- kuzatish uchun.inlinelambda uchun obyekt yaratilishining oldini oladi.
Keyingi bo'limda generiklarni o'rganamiz.
O‘qish tarixini saqlamoqchimisiz?
Tizimga kirsangiz, tugatgan bo‘limlaringiz saqlanadi va qoldirgan joyingizdan davom etasiz.
Xatolik topdingizmi?
Imlo xatosi, ishlamaydigan kod yoki noto‘g‘ri ma‘lumotni ko‘rsangiz - bizga xabar bering. Har bir xabar administrator tomonidan ko‘rib chiqiladi.