12-bo‘lim
data class, object va enum
data class bir qatorda nimalarni beradi, copy va yoyish, object bilan yakka nusxa, companion object va enum sinflari.
Ushbu bo‘lim mundarijasi
Kotlin da uch xil maxsus sinf bor. Har biri ma'lum bir vazifani juda qisqa hal qiladi.
data class #
data class Talaba(val ism: String, val ball: Int)
fun main() {
val a = Talaba("Malika", 88)
val b = Talaba("Malika", 88)
println(a)
println(a == b)
println(a.hashCode() == b.hashCode())
println(a.ism)
}
Talaba(ism=Malika, ball=88)
true
true
Malika
Bitta so'z - data - qo'shildi va kompilyator to'rtta narsani
yozib berdi:
| Nima | Vazifasi |
|---|---|
toString() | O'qishga qulay ko'rinish |
equals() | Mazmun bo'yicha solishtirish |
hashCode() | Set va Map da to'g'ri ishlash |
copy() | Nusxa olish |
componentN() | Yoyish uchun |
Oldingi bo'limda buni qo'lda yozgandik - yigirmaga yaqin qator edi.
copy #
data class Talaba(val ism: String, val ball: Int, val guruh: String)
fun main() {
val asl = Talaba("Malika", 88, "A")
val yangiBall = asl.copy(ball = 95)
val boshqaGuruh = asl.copy(guruh = "B")
val toliqNusxa = asl.copy()
println(asl)
println(yangiBall)
println(boshqaGuruh)
println(asl == toliqNusxa)
println(asl === toliqNusxa)
}
Talaba(ism=Malika, ball=88, guruh=A)
Talaba(ism=Malika, ball=95, guruh=A)
Talaba(ism=Malika, ball=88, guruh=B)
true
false
copy - "shu obyektning nusxasini ol, faqat bu maydonni
o'zgartir". val xossalar o'zgarmasligi uchun bu asosiy o'zgartirish
usuli.
data class ni odatda faqat val bilan yozadilar.
Obyektni o'zgartirish o'rniga - yangi nusxa yaratiladi. Bu dastlab g'alati tuyuladi, lekin katta foyda beradi: obyektni funksiyaga uzatganingizda, u sizning nusxangizni o'zgartirib qo'ymasligiga ishonch hosil qilasiz.
Ayniqsa ko'p oqimli dasturda bu muhim - o'zgarmas obyekt hech qachon "yarim o'zgargan" holatda ko'rinmaydi.
Yoyish #
data class Nuqta(val x: Int, val y: Int)
fun main() {
val n = Nuqta(3, 7)
val (x, y) = n
println("x=$x, y=$y")
val nuqtalar = listOf(Nuqta(1, 2), Nuqta(3, 4))
for ((a, b) in nuqtalar) {
println("$a-$b")
}
val (ism, ball) = Pair("Aziza", 95)
println("$ism: $ball")
}
x=3, y=7
1-2
3-4
Aziza: 95
val (x, y) = n - yoyish (destructuring). U componentN()
funksiyalariga tayanadi va ularni data class avtomatik yozadi.
val (x, y) = nuqta da x birinchi maydonni, y ikkinchisini
oladi - nomlari qanday bo'lishidan qat'i nazar.
Ya'ni val (y, x) = nuqta deb yozsangiz, qiymatlar almashib
ketadi va kompilyator hech narsa demaydi.
Shuning uchun uch-to'rtta maydondan ko'p bo'lsa, yoyish o'rniga
nuqta.x deb yozgan xavfsizroq.
data class cheklovlari #
equals, hashCode, toString va copy faqat asosiy
konstruktordagi xossalarni ko'radi.
data class Talaba(val ism: String) {
var ball: Int = 0
}
Bu yerda ball - tanadagi xossa, shuning uchun ikki obyekt turli
ballar bilan ham teng hisoblanadi. Bu ko'pincha kutilmagan
natija beradi.
Qoida: taqqoslashga kirishi kerak bo'lgan hamma narsani asosiy konstruktorga qo'ying.
data class Talaba(val ism: String) {
var ball: Int = 0
}
fun main() {
val a = Talaba("Malika")
val b = Talaba("Malika")
a.ball = 88
b.ball = 50
println(a == b)
println(a)
}
true
Talaba(ism=Malika)
Ko'rib turganingizdek, ball na taqqoslashda, na toString da
qatnashdi.
object - yakka nusxa #
object Sozlama {
var til = "uz"
val versiya = "1.0"
fun korsat() = "Til: $til, versiya: $versiya"
}
fun main() {
println(Sozlama.korsat())
Sozlama.til = "en"
println(Sozlama.til)
val a = Sozlama
val b = Sozlama
println(a === b)
}
Til: uz, versiya: 1.0
en
true
object - sinf va uning yagona nusxasi bir vaqtda. Uni
new qilish kerak emas va ikkinchi nusxa hech qachon yaratilmaydi.
Bu singleton namunasi bo'lib, boshqa tillarda uni qo'lda yozish kerak bo'ladi.
companion object #
class Talaba private constructor(val ism: String, val ball: Int) {
companion object {
const val ENG_YUQORI = 100
fun yarat(ism: String, ball: Int): Talaba? {
if (ball !in 0..ENG_YUQORI) return null
return Talaba(ism, ball)
}
fun bosh() = Talaba("noma'lum", 0)
}
override fun toString() = "$ism ($ball)"
}
fun main() {
println(Talaba.ENG_YUQORI)
println(Talaba.yarat("Malika", 88))
println(Talaba.yarat("Xato", 150))
println(Talaba.bosh())
}
100
Malika (88)
null
noma'lum (0)
companion object - sinfga tegishli (obyektga emas) a'zolar uchun.
Boshqa tillardagi static ning o'rnini bosadi.
Bu yerda konstruktor private qilingan va obyekt faqat yarat
orqali yaratiladi - u qiymatni tekshiradi va noto'g'ri bo'lsa null
qaytaradi.
Kotlin da static kalit so'zi umuman yo'q.
Uning o'rnida uch vosita bor:
- Yuqori darajadagi funksiya va o'zgaruvchi - fayl ichida, sinfdan tashqarida. Ko'p hollarda eng to'g'ri tanlov.
object- holatga ega yakka nusxa kerak bo'lsa.companion object- a'zo aynan shu sinfga bog'liq bo'lsa.
Yordamchi funksiya yozayotgan bo'lsangiz, uni sinfga tiqishdan oldin o'ylab ko'ring: balki oddiy yuqori darajadagi funksiya yetarlidir.
enum class #
enum class Holat {
YANGI, KORILMOQDA, BAJARILDI
}
fun main() {
val h = Holat.KORILMOQDA
println(h)
println(h.name)
println(h.ordinal)
println(Holat.valueOf("YANGI"))
println(Holat.entries)
println(Holat.entries.joinToString(" ") { "${it.ordinal}:${it.name}" })
}
KORILMOQDA
KORILMOQDA
1
YANGI
[YANGI, KORILMOQDA, BAJARILDI]
0:YANGI 1:KORILMOQDA 2:BAJARILDI
Diqqat: println(h) nomni chiqardi. Ba'zi tillarda bu yerda
raqam chiqadi - Kotlin da esa yo'q.
enum - xossalar bilan #
enum class Daraja(val chegara: Int, val belgi: String) {
PAST(0, "-"),
ORTA(60, "+"),
YUQORI(85, "*");
fun tavsif() = "$name (${chegara}dan yuqori) $belgi"
}
fun baho(ball: Int): Daraja = when {
ball >= Daraja.YUQORI.chegara -> Daraja.YUQORI
ball >= Daraja.ORTA.chegara -> Daraja.ORTA
else -> Daraja.PAST
}
fun main() {
for (d in Daraja.entries) {
println(d.tavsif())
}
println(baho(92))
println(baho(70))
println(baho(30))
}
PAST (0dan yuqori) -
ORTA (60dan yuqori) +
YUQORI (85dan yuqori) *
YUQORI
ORTA
PAST
enum da konstruktor, xossa va metod bo'lishi mumkin. Qiymatlar
ro'yxatidan keyin nuqtali vergul qo'yiladi - bu Kotlin da
nuqtali vergul haqiqatan kerak bo'ladigan kam joylardan biri.
when va enum #
enum class Yonalish { SHIMOL, JANUB, SHARQ, GARB }
fun teskari(y: Yonalish): Yonalish = when (y) {
Yonalish.SHIMOL -> Yonalish.JANUB
Yonalish.JANUB -> Yonalish.SHIMOL
Yonalish.SHARQ -> Yonalish.GARB
Yonalish.GARB -> Yonalish.SHARQ
}
fun main() {
for (y in Yonalish.entries) {
println("$y -> ${teskari(y)}")
}
}
SHIMOL -> JANUB
JANUB -> SHIMOL
SHARQ -> GARB
GARB -> SHARQ
Yuqoridagi when da else tarmog'i yo'q - va kompilyator
shikoyat qilmadi.
Sababi: u Yonalish ning hamma qiymati qamrab olinganini ko'rdi.
Bu katta afzallik: enum ga yangi qiymat qo'shsangiz, kompilyator
shu when ni ko'rsatib, "bu holat qamrab olinmagan" deydi. else
yozgan bo'lsangiz, xato jimgina o'tib ketardi.
Kitobnidata classqilib yozing vaprintlnbilan chiqaring.- Ikkita bir xil obyektni
==bilan solishtiring. copybilan faqat narxni o'zgartirgan nusxa oling.val (a, b) = obyektbilan yoying.- Tanadagi xossa
equalsga kirmasligini isbotlang. objectbilan sozlamalar saqlovchi yakka nusxa yarating.companion objectda yaratuvchi funksiya yozing.- Konstruktorni
privateqilib, faqat shu funksiya orqali yarating. - Hafta kunlari uchun
enumyozing. enumga xossa qo'shing vawhendaelsesiz ishlating.
Xulosa #
data classbir so'z bilantoString,equals,hashCode,copyva yoyishni beradi.copy(maydon = yangi)- o'zgarmas obyektni "o'zgartirish" usuli.- Yoyish tartibga bog'liq, nomga emas.
equalsvatoStringfaqat asosiy konstruktordagi xossalarni ko'radi.object- singleton;companion object- sinfga tegishli a'zolar.- Kotlin da
staticyo'q; ko'pincha yuqori darajadagi funksiya yetarli. enumdaprintlnnomni chiqaradi;entrieshamma qiymatni beradi.enumbilanwhendaelsekerak emas - bu kelajakdagi xatolardan saqlaydi.
Keyingi bo'limda vorislik, interfeys va sealed sinflarni ko'ramiz.
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.