1. Niyə when-i ifadə kimi istifadə etməli
Konsol proqramları yazanda, “hər budaqda println(...)” stilinə yuvarlanmaq çox asandır. Bu işləyir... proqram kiçik olana qədər. Amma siz əvvəlcə mesaj mətnini hesablamaq, sonra onu hara göndərəcəyinizə qərar vermək (konsola, loqa, fayla) istəyəndə və ya funksiyadan nəticə qaytarmaq istəyəndə — sizə qəfil when lazımdır: o, sadəcə hərəkət icra etmir, dəyər qaytarır.
Kotlin-da when həm operator (statement), həm də ifadə (expression) ola bilər. Fərq ondadır ki, ifadə nəticə verir — onu dəyişənə mənimsətmək və ya funksiyadan qaytarmaq olar. Kotlin bu fikri birbaşa vurğulayır: when ifadə kimi dəyər qaytarır, operator kimi isə nəticəsiz sadəcə kodu icra edir.
Mini-paralel: operator vs ifadə
| Nə istəyirik | Necə yazırıq | Nə alırıq |
|---|---|---|
| “Hərəkət et” | |
Heç nə qaytarmırıq, sadəcə icra edirik |
| “Dəyər qaytar” | |
Dəyər alırıq və sonra istifadə edirik |
Bu ideya rəsmi izahda when-in expression vs statement kimi istifadəsində eyni cür təsvir olunur.
2. Baza sintaksis: val result = when (...) { ... }
İndi günün ən vacib addımını edirik: when-in içində çap etməyi dayandırırıq (bəzən olar, amma), və nəticə kimi sətir/rəqəm almağa başlayırıq. Bu, əvvəldən gördüyünüz ifadə kimi if-ə bənzəyir: “budaqlanma nəsə edir” modelindən “budaqlanma dəyər seçir” modelinə keçirik.
Açar forma belə görünür:
val message = when (x) {
1 -> "..."
2 -> "..."
else -> "..."
}
Burada message — adi dəyişəndir, when (...) {...} isə “hesablanaraq” tək bir dəyərə çevrilən ifadədir.
Nümunə 1: cavab koduna görə mesaj seçirik
fun main() {
val code = 404
val message = when (code) {
200 -> "OK"
404 -> "Not Found"
else -> "Basqa kod: $code"
}
println(message) // Not Found
}
Diqqət edin: budaqların içində çap etmirik. Biz sətirlər qaytarırıq, çapı isə bir dəfə — when-dən sonra edirik. Bu dərhal qayda yaradır: “əvvəl nə deyəcəyimizi qərarlaşdırırıq, sonra deyirik”.
3. Exhaustiveness və else
İndi bu leksiyanın əsas “stop-kadr”ı. when operator (statement) kimi istifadə olunanda, Kotlin bütün variantları əhatə etməməyə icazə verir: heç bir budaq uyğun gəlməsə — sadəcə heç nə baş verməyəcək. Rəsmi nümunə məhz bu davranışı göstərir: bütün hallar örtülməyib, budaq seçilməyib, amma xəta yoxdur.
Amma when ifadə kimi istifadə olunanda, Kotlin exhaustiveness tələb edir: ifadənin istənilən girişdə mütləq nəticəsi olmalıdır. Yoxsa dəyişənə nə mənimsədək? “Boşluq”? Kompilyator razılaşmır.
Kotlin bunu birbaşa belə formalaşdırır: əgər when ifadə kimi istifadə olunursa, siz mütləq bütün halları örtməlisiniz, yoxsa kompilyasiya xətası olacaq.
Həyatda xəta necə görünür
Təsəvvür edin, bunu yazmısınız:
fun main() {
val code = 500
val message = when (code) {
200 -> "OK"
404 -> "Not Found"
// else yoxdur
}
println(message)
}
Məntiq aydındır: “hələlik mənə yalnız 200 və 404 vacibdir”. Amma kompilyator təxminən belə deyəcək: “bəs code 500 olarsa nə etməliyik?” — və haqlıdır. Ona görə də ifadə kimi when-də çox vaxt else görünür.
“else məcburi deyil” — amma hələ sevinməyə tələsməyək
Nəzəri olaraq, bütün variantları zəmanətli şəkildə sadalamısınızsa, else yazmaya bilərsiniz. Kotlin-da bunun real olduğu tiplər var (məsələn, bəzi qapalı dəyərlər toplusu üçün), amma orada sonradan kursda ətraflı müzakirə edəcəyimiz tiplər ortaya çıxır.
Hazırkı səviyyədə yeni başlayan üçün dürüst qaydanı yadda saxlamaq daha asandır: əgər when dəyər qaytarırsa — həmişə else lazımdır.
4. Budağın dəyəri: -> və blok { ... }
when-də budaq ->-dan sonra bir sətirdirsə, hər şey sadədir: elə həmin dəyər qaytarılır. Amma çox tez budağın içində bir neçə addım etmək istəyəcəksiniz: məsələn, mətni hazırlamaq, məlumatı bir az normallaşdırmaq və ya nəyisə mərhələlərlə hesablamaq. Onda budaq blok olur: { ... }.
Və burada qaydanı bilmək vacibdir: budaq-blokun dəyəri — blokun içindəki son ifadədir. Kotlin vurğulayır ki, budaq blok ola bilər və onun dəyəri həmin blokun son ifadəsinin dəyəri olacaq.
Nümunə 2: budaq-blok son ifadəni qaytarır
fun main() {
val code = 400
val message = when (code) {
200 -> "OK"
400 -> {
val base = "Bad Request"
"$base (giris melumatlarini yoxlayin)"
}
else -> "Basqa kod: $code"
}
println(message) // Bad Request (giris melumatlarini yoxlayin)
}
Burada budağın içində base dəyişənini hazırladıq, son sətirdə isə şablon-sətiri qaytardıq.
Həyat saatlarına qənaət edən nüans
Əgər budaqda son sətir println(...) olsa, budaq Unit qaytaracaq və “əyləncə” başlayacaq: müxtəlif budaqlar müxtəlif tiplər qaytarır. Ona görə də when-i ifadə kimi istifadə edəndə budaqları “qaytaran”, çapı isə kənarda saxlamağa çalışın.
5. when nəticəsinin tipi: bütün budaqlar uzlaşmalı olmalıdır
when ifadə olanda onun tək bir nəticəsi var, deməli tək bir tipi var. Kotlin bütün budaqlar üçün ümumi tip çıxarmağa çalışacaq. Əgər bir budaq String, digəri Int, üçüncüsü isə ümumiyyətlə Unit qaytarırsa, ümumi tip çox “geniş” olur (məsələn, Any) və sonra bunu istifadə etmək narahatdır.
Texniki formalaşdırma əvəzinə praktik olanı yadda saxlayaq: əvvəlcədən qərar verin, sizin when nə qaytarır. Əgər bu mesajdırsa — qoy bütün budaqlar String qaytarsın. Əgər rəqəmdirsə — qoy rəqəm qaytarsın.
Nümunə 3: when rəqəm qaytarır
fun main() {
val month = 2
val daysInMonth = when (month) {
1, 3, 5, 7, 8, 10, 12 -> 31
4, 6, 9, 11 -> 30
2 -> 28
else -> 0
}
println(daysInMonth) // 28
}
Bəli, burada vergül ilə dəyərləri qruplaşdırdıq — bu qanunidir və oxunaqlıdır; Kotlin belə stili when üçün standart qəbul kimi göstərir.
Və buradakı else -> 0 “gözəllik üçün” deyil: “istifadəçi 13 daxil edib” halını bağlayır. Hələ diapazonları gözəl şəkildə validasiya etmirik — bu növbəti leksiya olacaq — amma exhaustiveness artıq indi lazımdır.
6. Praktika: funksiyalarda when, null ilə və else-siz
Real proqramlarda budaqlanma tez-tez funksiyaların içində yaşayır: “kodu al — mətni qaytar”, “komandanı al — ipucunu qaytar”. Kotlin hətta stil razılaşmalarında dəyər qaytardığınız yerlərdə if/when/try-ın ifadə formasını istifadə etməyi tövsiyə edir, çünki bu kodu daha qısa və daha birbaşa edir.
Daha sonra — when-in ifadə kimi xüsusilə yaxşı olduğu bir neçə tipik vəziyyət.
when + funksiyalar: if-dən “əriştə”siz dəyər qaytarırıq
Gəlin gələcək konsol tətbiqimiz üçün kiçik bir funksiya düzəldək (günün növbəti leksiyalarında komandaları emal etməyə başlayacağıq). Hələ giriş olmadan — sadəcə arxitekturanı görmək üçün: funksiya sətir qaytarır.
fun statusText(code: Int): String = when (code) {
200 -> "OK"
400 -> "Bad Request"
404 -> "Not Found"
else -> "Unknown: $code"
}
fun main() {
println(statusText(404)) // Not Found
}
Bu, demək olar ki, lüğət kimi oxunur: “200 — OK, 400 — Bad Request...”. Və əsas məsələ: funksiya həmişə sətir qaytarır, çünki when exhaustiveness-i təmin edir.
Nullable dəyərlər when-də: ayrıca null budağı
İndi çox həyatilik bir hekayə: istifadəçi nəsə daxil etdi, siz parse etməyə çalışdınız, Int? aldınız (yəni “rəqəm və ya null”), və sonra gözəl reaksiya verməlisiniz.
Burada when xüsusilə rahatdır, çünki null-u ayrıca budaqla emal etmək olar. Bu, əvvəlki toIntOrNull() təcrübəmiz və baza null-safety ilə təbii şəkildə uyğunlaşır.
fun main() {
print("Yasi daxil edin: ")
val raw = readln().trim()
val age: Int? = raw.toIntOrNull()
val message = when (age) {
null -> "Bu reqeme oxsamir: \"$raw\""
0 -> "Yas 0 — proqramci karyerasinin baslangici kimi seslenir."
else -> "Sizin yasiniz: $age"
}
println(message)
}
Burada vacib olan budur ki, message istənilən ssenaridə sətirdir. Hətta age == null olsa belə, yenə də sətir qaytarırıq — deməli when exhaustiveness-i saxlayır.
Mini-refaktorinq: “konsol komekcisi” — evvel cavabi formalaşdir, sonra cap et
İndi komandalar haqqında leksiyada xüsusilə faydalı olacaq stili yığmağa başlayırıq. Təsəvvür edək ki, bizdə “konsol köməkçisi” var — komanda ilə reaksiya verən və mətn çıxaran tətbiq. Hələ readln() və normallaşdırma olmadan (bu növbəti səviyyə leksiyası olacaq), sadəcə eskiz.
Bu leksiyanın əsas ideyası: budaqlanma sətir qaytarır, çap isə bir dəfə edilir.
fun replyFor(command: String): String = when (command) {
"help" -> "Movcud komandalar: help, exit"
"exit" -> "Isimi bitirirem..."
else -> "Naməlum komanda: $command"
}
fun main() {
val cmd = "help"
val reply = replyFor(cmd)
println(reply) // Movcud komandalar: help, exit
}
Baxın nə qədər rahatdır: replyFor(...)-u sonra yenidən istifadə etmək olar. Növbəti leksiyada siz istifadəçi daxilindən command-i “çıxarmağı”, trim().lowercase() ilə normallaşdırmağı öyrənəcəksiniz və onda when birbaşa komanda dispetcerinə çevriləcək. Amma təməl məhz buradadır: when ifadə kimi nəticə qaytarır.
when else-siz: Boolean üzərində nümunə
Exhaustiveness-in mahiyyətini anlamaq üçün, else-in həqiqətən lazım olmadığı halı görmək faydalıdır — sadəcə “else yaz”ı əzbərləmək üçün yox.
Boolean-ın cəmi iki dəyəri var və əgər siz true və false-u emal etmisinizsə, deməli hamısını emal etmisiniz. Bu halda when else-siz exhaustiveness-i təmin edir.
fun main() {
val isAdmin = true
val access = when (isAdmin) {
true -> "Giris: tam"
false -> "Giris: mehdud"
}
println(access) // Giris: tam
}
Bəs niyə mən yenə də sizə fanatik şəkildə else-dən qaçmağı məsləhət görmürəm? Çünki nullable məntiq (Boolean?) ortaya çıxan kimi və ya daha mürəkkəb tip düzəltdiyiniz kimi, “hər şey örtülüb” qəfil aydın olmaya bilər. Sizin indiki mərhələdə else düşmən deyil, kompilyator və istifadəçi sürprizlərinə qarşı sığortadır.
7. when-i ifadə kimi istifadə edərkən tipik səhvlər
Sehv №1: else-i unutmaq və “niyə qəfil kompilyator əsəbiləşir?” deyə təəccüblənmək.
Bu, ən çox rast gəlinən vəziyyətdir: siz gözəl budaqlanma yazmısınız, onu val-a mənimsətmisiniz və gözləyirsiniz ki, uyğun gəlməsə proqram sadəcə “heç nə etməyəcək”. Amma ifadə dəyər qaytarmalıdır, ona görə else (və ya hallarının tam dəsti) mütləq lazımdır. Bu Kotlin-in kaprizi deyil, məntiqdir: əks halda nəyi mənimsətmək lazım olduğu aydın deyil.
Sehv №2: müxtəlif budaqlardan müxtəlif tiplər qaytarmaq və qəribə ümumi tip almaq.
Məsələn, bir budaqda "OK", digərində 0 qaytarmaq, üçüncüdə isə println(...) etmək. Kotlin ümumi tip axtarmağa başlayacaq və siz işləməsi narahat olan nəticə alacaqsınız. Yaxşı stil — when-in “kontrakt”ını əvvəlcədən seçməkdir: sətir qaytarırıq ya rəqəm qaytarırıq və bütün budaqlarda buna sadiq qalırıq.
Sehv №3: budaqların içində (println) çap etmək, sonra isə nəticəni istifadə etməyə çalışmaq.
Bu, “mən if/else-ə öyrəşmişəm, orada hərəkət edirdim” tələsidir. Əgər budağın içində println(...) durursa, bu dəyər deyil, hərəkətdir. Nəticədə ya ümumiyyətlə mənimsədə bilməyəcəksiniz, ya da Unit alacaqsınız. Praktik fənd: əvvəlcə val message = when (...) { ... } hesablayın, sonra kənarda bir dəfə println(message) edin.
Sehv №4: budaqları blok etmək, amma qaydanı unutmaq: dəyər son ifadədir.
Bəzən insan budaqda blok yazır, dəyişənlər yaradır, amma son sətirdə təsadüfən “lazım olmayan” bir şey saxlayır (məsələn, Unit qaytaran funksiya çağırışı). Nəticədə budaq Unit qaytarır və when-in nəticə tipi pozulur. Əgər budaq blokdursa, özünüzə düşüncədə sual verin: “son sətir hansıdır və nə qaytarır?” Kotlin birbaşa “son ifadə — budağın dəyəridir” qaydasını təsvir edir.
Sehv №5: when-in içində hər şeyi qarışdırmaq: hesablamaları da, girişi də, çapı da, xətaların emalını da.
İşləsə belə, belə kodu oxumaq çətindir: when “proqramın içində kiçik proqram”a çevrilir. Budaqları qısa saxlayın: qoy when “hansı nəticəni seçməliyik?” sualına cavab versin, qalan hərəkətlər (giriş/çap) isə yanında və ayrıca aydın olsun. Bu stil — Kotlin-in kod razılaşmalarında şərti konstruksiyaların ifadə formasını üstün tutmasının səbəblərindən biridir: məntiqi daha birbaşa edir.
GO TO FULL VERSION