20-bo‘lim
Amaliy loyiha - vazifalar daftari
O'rganilgan hamma narsani birlashtirib, vazifalarni yozadigan, filtrlaydigan, hisobot beradigan va faylga saqlaydigan to'liq dastur yozamiz.
Ushbu bo‘lim mundarijasi
Endi barcha bo'limlarni birlashtiramiz. Yozadigan dasturimiz - vazifalar daftari: vazifa qo'shadi, bajarilganini belgilaydi, hisobot beradi va faylga saqlaydi.
Dasturni bosqichma-bosqich quramiz va har bir bosqichni ishga tushirib ko'ramiz.
1-bosqich: model #
Avval ma'lumot shaklini belgilaymiz. Bu ta'riflar butun bob davomida ishlatiladi:
enum class Muhimlik(val belgi: String, val vazn: Int) {
PAST("-", 1),
ORTA("=", 2),
YUQORI("!", 3);
override fun toString() = name.lowercase()
}
data class Vazifa(
val id: Int,
val matn: String,
val muhimlik: Muhimlik = Muhimlik.ORTA,
val bajarildi: Boolean = false
) {
val korinishi: String
get() {
val belgi = if (bajarildi) "x" else " "
return "[$belgi] ${muhimlik.belgi} #$id $matn"
}
}
Sinab ko'ramiz:
fun main() {
val a = Vazifa(1, "Kotlin o'rganish", Muhimlik.YUQORI)
val b = Vazifa(2, "Non olish")
println(a.korinishi)
println(b.korinishi)
println(a)
val bajarilgan = a.copy(bajarildi = true)
println(bajarilgan.korinishi)
println(a.bajarildi)
}
[ ] ! #1 Kotlin o'rganish
[ ] = #2 Non olish
Vazifa(id=1, matn=Kotlin o'rganish, muhimlik=yuqori, bajarildi=false)
[x] ! #1 Kotlin o'rganish
false
Diqqat qiling:
data classtoStringni o'zi yozdi.copy(bajarildi = true)yangi obyekt yasadi -ao'zgarmadi.enumga xossa (belgi,vazn) vatoStringqo'shildi.korinishi- hisoblanadigan xossa, saqlanmaydi.
2-bosqich: daftar #
class Daftar {
private val vazifalar = mutableListOf<Vazifa>()
private var keyingiId = 1
val soni: Int get() = vazifalar.size
fun qosh(matn: String, muhimlik: Muhimlik = Muhimlik.ORTA): Vazifa {
require(matn.isNotBlank()) { "Vazifa matni bo'sh bo'lmasligi kerak" }
val yangi = Vazifa(keyingiId++, matn.trim(), muhimlik)
vazifalar.add(yangi)
return yangi
}
fun bajar(id: Int): Boolean {
val i = vazifalar.indexOfFirst { it.id == id }
if (i == -1) return false
vazifalar[i] = vazifalar[i].copy(bajarildi = true)
return true
}
fun ochir(id: Int): Boolean = vazifalar.removeIf { it.id == id }
fun hammasi(): List<Vazifa> = vazifalar.toList()
fun kutilayotgan(): List<Vazifa> =
vazifalar.filter { !it.bajarildi }
.sortedWith(compareByDescending<Vazifa> { it.muhimlik.vazn }
.thenBy { it.id })
fun topish(soz: String): List<Vazifa> =
vazifalar.filter { it.matn.contains(soz, ignoreCase = true) }
}
fun main() {
val d = Daftar()
d.qosh("Kotlin o'rganish", Muhimlik.YUQORI)
d.qosh("Non olish", Muhimlik.PAST)
d.qosh("Hisobot yozish", Muhimlik.YUQORI)
d.qosh("Kitob o'qish")
println("Jami: ${d.soni}")
d.bajar(2)
println("-- Kutilayotganlar --")
d.kutilayotgan().forEach { println(it.korinishi) }
println("-- Qidiruv: 'o' --")
d.topish("o").forEach { println(it.korinishi) }
println(d.bajar(99))
}
Jami: 4
-- Kutilayotganlar --
[ ] ! #1 Kotlin o'rganish
[ ] ! #3 Hisobot yozish
[ ] = #4 Kitob o'qish
-- Qidiruv: 'o' --
[ ] ! #1 Kotlin o'rganish
[x] - #2 Non olish
[ ] ! #3 Hisobot yozish
[ ] = #4 Kitob o'qish
false
Oxirgi false - d.bajar(99) natijasi: bunday id yo'q, shuning
uchun metod istisno ko'tarmasdan false qaytardi.
Bu yerda ishlatilgan vositalar:
require- bo'sh matnni rad etadi (17-bo'lim).indexOfFirstvacopy- o'zgarmas obyektni "yangilash".compareByDescending { }.thenBy { }- ikki mezon bo'yicha saralash.contains(soz, ignoreCase = true)- katta-kichik harfsiz qidiruv.hammasi()nusxa qaytaradi -toList()shuning uchun.
hammasi() da vazifalar ni to'g'ridan-to'g'ri qaytarsa bo'lardi -
turi List bo'lgani uchun tashqaridan add chaqirib bo'lmasdi.
Lekin uni MutableList ga aylantirib olish mumkin:
(d.hammasi() as MutableList).clear()
toList() esa haqiqiy nusxa yasaydi - bunday hiyla ishlamaydi.
3-bosqich: hisobot #
fun hisobot(d: Daftar): String {
val hammasi = d.hammasi()
if (hammasi.isEmpty()) return "Daftar bo'sh"
val bajarilgan = hammasi.count { it.bajarildi }
val foiz = bajarilgan * 100.0 / hammasi.size
val quruvchi = StringBuilder()
quruvchi.appendLine("MUHIMLIK JAMI BAJARILDI")
quruvchi.appendLine("-".repeat(28))
Muhimlik.entries.sortedByDescending { it.vazn }.forEach { m ->
val guruh = hammasi.filter { it.muhimlik == m }
if (guruh.isNotEmpty()) {
quruvchi.appendLine(
m.name.padEnd(12) +
guruh.size.toString().padStart(4) +
guruh.count { it.bajarildi }.toString().padStart(11)
)
}
}
quruvchi.appendLine("-".repeat(28))
val f = "%.0f".format(foiz)
quruvchi.append("Bajarilgan: $bajarilgan/${hammasi.size} ($f%)")
return quruvchi.toString()
}
fun main() {
val d = Daftar()
d.qosh("Kotlin o'rganish", Muhimlik.YUQORI)
d.qosh("Non olish", Muhimlik.PAST)
d.qosh("Hisobot yozish", Muhimlik.YUQORI)
d.qosh("Kitob o'qish")
d.qosh("Sport", Muhimlik.PAST)
d.bajar(2)
d.bajar(3)
println(hisobot(d))
println()
println(hisobot(Daftar()))
}
MUHIMLIK JAMI BAJARILDI
----------------------------
YUQORI 2 1
ORTA 1 0
PAST 2 1
----------------------------
Bajarilgan: 2/5 (40%)
Daftar bo'sh
Muhimlik.entries - enum ning hamma qiymati (12-bo'lim). Uni
vazn bo'yicha saralab, tartibni o'zimiz belgiladik.
4-bosqich: faylga saqlash #
import java.io.File
fun Vazifa.qatorga(): String =
listOf(id, matn, muhimlik.name, bajarildi).joinToString("|")
fun qatordan(qator: String): Vazifa? {
val q = qator.split("|")
if (q.size != 4) return null
val id = q[0].toIntOrNull() ?: return null
val muhimlik = runCatching { Muhimlik.valueOf(q[2]) }.getOrNull()
?: return null
return Vazifa(id, q[1], muhimlik, q[3].toBoolean())
}
fun saqla(d: Daftar, fayl: File) {
fayl.writeText(d.hammasi().joinToString("\n") { it.qatorga() })
}
fun yukla(fayl: File): List<Vazifa> {
if (!fayl.exists()) return emptyList()
return fayl.readLines()
.filter { it.isNotBlank() }
.mapNotNull { qatordan(it) }
}
fun main() {
val fayl = File("vazifalar.txt")
val d = Daftar()
d.qosh("Kotlin o'rganish", Muhimlik.YUQORI)
d.qosh("Non olish", Muhimlik.PAST)
d.bajar(2)
saqla(d, fayl)
println("Saqlandi:")
println(fayl.readText())
println("-- Yuklandi --")
yukla(fayl).forEach { println(it.korinishi) }
fayl.writeText("bu|buzuq\nyana|buzuq|qator|va|ortiqcha")
println("Buzuq fayldan: ${yukla(fayl).size} ta")
println("Yo'q fayldan: ${yukla(File("yoq.txt")).size} ta")
fayl.delete()
}
Saqlandi:
1|Kotlin o'rganish|YUQORI|false
2|Non olish|PAST|true
-- Yuklandi --
[ ] ! #1 Kotlin o'rganish
[x] - #2 Non olish
Buzuq fayldan: 0 ta
Yo'q fayldan: 0 ta
Diqqat: buzuq fayl ham, mavjud bo'lmagan fayl ham dasturni to'xtatmadi. Yaxshi dasturning belgisi shu.
Bu yerda Vazifa.qatorga() - kengaytma funksiyasi (14-bo'lim).
U Vazifa sinfiga tegmasdan unga saqlash qobiliyatini qo'shdi.
5-bosqich: natijani ifodalash #
Foydalanuvchi buyrug'ining natijasini sealed bilan ifodalaymiz
(13-bo'lim):
sealed interface Javob {
data class Muvaffaqiyat(val xabar: String) : Javob
data class Xato(val sabab: String) : Javob
data object Chiqish : Javob
}
fun buyruq(d: Daftar, satr: String): Javob {
val qismlar = satr.trim().split(" ", limit = 2)
val amal = qismlar.firstOrNull()?.lowercase()
?: return Javob.Xato("bo'sh")
val arg = qismlar.getOrNull(1)?.trim()
return when (amal) {
"qosh" -> {
if (arg.isNullOrBlank()) return Javob.Xato("matn kerak")
val v = d.qosh(arg)
Javob.Muvaffaqiyat("Qo'shildi: #${v.id}")
}
"bajar" -> {
val id = arg?.toIntOrNull() ?: return Javob.Xato("id kerak")
if (d.bajar(id)) Javob.Muvaffaqiyat("Bajarildi: #$id")
else Javob.Xato("#$id topilmadi")
}
"ochir" -> {
val id = arg?.toIntOrNull() ?: return Javob.Xato("id kerak")
if (d.ochir(id)) Javob.Muvaffaqiyat("O'chirildi: #$id")
else Javob.Xato("#$id topilmadi")
}
"chiqish" -> Javob.Chiqish
else -> Javob.Xato("noma'lum buyruq: $amal")
}
}
fun main() {
val d = Daftar()
val buyruqlar = listOf(
"qosh Kotlin o'rganish",
"qosh Non olish",
"bajar 1",
"bajar 99",
"ochir abc",
"qosh",
"sakrash",
"chiqish"
)
for (b in buyruqlar) {
val javob = buyruq(d, b)
val belgi = when (javob) {
is Javob.Muvaffaqiyat -> "OK ${javob.xabar}"
is Javob.Xato -> "XATO ${javob.sabab}"
Javob.Chiqish -> "-- chiqildi --"
}
println("$belgi")
if (javob is Javob.Chiqish) break
}
println("Qolgan: ${d.soni} ta")
}
OK Qo'shildi: #1
OK Qo'shildi: #2
OK Bajarildi: #1
XATO #99 topilmadi
XATO id kerak
XATO matn kerak
XATO noma'lum buyruq: sakrash
-- chiqildi --
Qolgan: 2 ta
when (javob) da else yo'q - Javob sealed bo'lgani uchun
kompilyator hamma variant qamrab olinganini biladi. Yangi javob turi
qo'shsangiz, u shu yerni ko'rsatib xato beradi.
Interaktiv menyu #
Haqiqiy dasturda buyruqlar klaviaturadan o'qiladi. Bu darslikda misollar avtomatik tekshirilgani uchun uni ishga tushira olmaymiz, lekin shakli quyidagicha:
import java.io.File
fun main() {
val fayl = File("vazifalar.txt")
val d = Daftar()
yukla(fayl).forEach { d.qosh(it.matn, it.muhimlik) }
println("Buyruqlar: qosh <matn> | bajar <id> | ochir <id>")
println(" royxat | chiqish")
while (true) {
print("> ")
val satr = readlnOrNull() ?: break
if (satr.trim().lowercase() == "royxat") {
d.kutilayotgan().forEach { println(it.korinishi) }
continue
}
when (val javob = buyruq(d, satr)) {
is Javob.Muvaffaqiyat -> println(javob.xabar)
is Javob.Xato -> println("Xato: ${javob.sabab}")
Javob.Chiqish -> {
saqla(d, fayl)
println("Saqlandi. Xayr!")
return
}
}
}
}
readlnOrNull() - klaviaturadan bir qator o'qiydi va oqim tugasa
null qaytaradi.
Yuqoridagi buyruq funksiyasida har bir qadamda tekshiruv bor:
toIntOrNull, isNullOrBlank, getOrNull.
Foydalanuvchi "bajar abc" deb yozsa ham, "qosh" ni yolg'iz yozsa ham, dastur qulamaydi - u xushmuomala xabar beradi.
Bu kichik dasturda ortiqcha tuyulishi mumkin, lekin odat shu yerda shakllanadi.
Dastur tuzilishi #
Qaysi bo'lim qayerda ishlatildi #
| Bo'lim | Loyihada |
|---|---|
| 3 - Turlar | val, Int, Boolean |
| 4 - Satrlar | padEnd, padStart, shablonlar |
| 5 - when | buyruq() funksiyasi |
| 6 - Sikllar | forEach, for |
| 7 - Funksiyalar | Standart argumentlar, require |
| 8 - Null | ?:, toIntOrNull, isNullOrBlank |
| 9 - Kolleksiyalar | mutableListOf, toList |
| 10 - Amallar | filter, count, sortedWith, mapNotNull |
| 11 - Sinflar | Daftar, private maydon |
| 12 - data/enum | Vazifa, Muhimlik, copy |
| 13 - sealed | Javob |
| 14 - Kengaytma | Vazifa.qatorga() |
| 17 - Istisnolar | require, runCatching |
| 18 - Fayllar | saqla, yukla |
- Loyihani o'z kompyuteringizda yig'ib, ishga tushiring.
Muhimlikga yangi qiymat qo'shing va hisobotni tekshiring.- Vazifaga muddat (
sana) maydonini qo'shing. - Faqat bajarilganlarni qaytaruvchi metod yozing.
- Vazifa matnini tahrirlash imkonini qo'shing.
buyruq()garoyxatamalini qo'shing.Javobga yangi turi qo'shib, kompilyator nima deyishini ko'ring.- Hisobotni faylga saqlaydigan funksiya yozing.
- Bajarilgan vazifalarni tozalaydigan amal qo'shing.
- Fayl formatini CSV dan JSON ga o'zgartirishni rejalashtiring.
Xulosa #
- Katta dastur kichik qismlardan quriladi: model, qoidalar, hisobot, saqlash - har biri alohida.
data class+copy- o'zgarmas ma'lumot bilan ishlashning asosi.- Ichki ro'yxatni
toList()bilan nusxa qilib bering. sealednatijani ifodalash uchun ideal:whento'liq bo'ladi.- Kengaytma funksiyasi sinfga tegmasdan unga qobiliyat qo'shadi.
- Buzuq fayl yoki noto'g'ri kiritish dasturni to'xtatmasligi kerak.
- Foydalanuvchi ma'lumotini har doim
toIntOrNullvaisNullOrBlankbilan tekshiring.
Darslik yakuni #
Tabriklaymiz - siz Kotlin ning asoslarini o'rgandingiz:
val/var, turlar, satrlar vawhen- Sikllar, funksiyalar va null xavfsizligi
- Kolleksiyalar va ularning boy amallari
- Sinflar,
data class,object,enumvasealed - Kengaytmalar, lambda, qamrov funksiyalari va generiklar
- Istisnolar, fayllar va korutinlar
Keyingi qadamlar uchun uchta yo'nalish bor:
- Android - Google ning rasmiy tavsiyasi.
Jetpack Composebilan interfeys yozish bugungi standart. - Server -
Ktor(Kotlin uchun yozilgan) yokiSpring Bootbilan veb xizmatlar. - Ko'p platformali - bitta mantiqni Android va iOS uchun ulashish.
Eng muhimi - yozishni to'xtatmang. Har kuni kichik dastur yozish bir oyda katta farq qiladi.
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.