genişləndirmə funksiyası — Kotlin mexanizmi, mövcud siniflərə miras almadan və mənbə kodunu dəyişmədən yeni metodlar əlavə etməyə imkan verir. Funksiya qəbuledici tip prefiksi ilə elan edilir və bu tipin adi metodu kimi çağırılır. Kotlin Documentation, 2025-ə görə, genişləndirmə funksiyaları birinci parametr-qəbuledici ilə statik metodlara kompilyasiya olunur və bu, adi çağırışlarla müqayisədə sıfır overhead təmin edir.
Əsas məqamlar
Genişləndirmə funksiyası sinifdən kənarda elan edilmiş, lakin onun metodu kimi çağırılan funksiyadır. O, yeni metodun əlavə olunduğu qəbuledici tipi qəbul edir. Funksiya daxilində this açar sözü qəbuledici tipin nümunəsinə istinad edir. Bu yanaşma final sinifləri, üçüncü tərəf kitabxanalarının siniflərini və hətta primitiv tipləri sarğılar yaratmadan genişləndirməyə imkan verir.
Java-dan fərqli olaraq, mövcud sinifə metod əlavə etmək üçün ya miras, ya da statik yardımçı sinif tələb olunur, Kotlin boilerplate olmadan zərif həll təklif edir. Məlumatlara görə Kotlin Foundation (2024) tədqiqatında, genişləndirmə funksiyaları dilin ən çox istifadə olunan xüsusiyyətlərinin ilk beşliyinə daxildir — onu gündəlik işdə Kotlin tərtibatçılarının 78%-i tətbiq edir.
Kotlin kompilyatoru genişləndirmə funksiyasını statik metoda çevirir, burada birinci arqument kimi qəbuledici nümunəsi ötürülür. Bu o deməkdir ki, genişləndirmə funksiyaları hədəf sinfin bayt kodunu dəyişmir və inkapsulyasiyanı pozmur — qəbuledicinin yalnız açıq sahələri və metodları əlçatandır.
Genişləndirmə funksiyalarından məntiqi olaraq müəyyən tipə bağlı olan, lakin onun mənbə koduna əlavə edilə bilməyən təmiz yardımçı funksiyalar yazmaq üçün istifadə edin.
Genişləndirmə funksiyasının əsas sintaksisi: qəbuledici tipin adı, nöqtə, funksiya adı, sonra parametrlər və qaytarılan tip. Funksiya daxilində qəbuledici this vasitəsilə əlçatandır.
// String üçün genişləndirmə funksiyası
fun String.isEmail(): Boolean {
return this.contains("@") && this.contains(".")
}
// Adi String metodu kimi çağırılır
val result = "user@example.com".isEmail() // true
Bu nümunədə isEmail() bütün sətirlər üçün əlçatan olur. Funksiya daxilində this metodun çağırıldığı sətirin özüdür. Kotlin əksər hallarda this-i buraxmağa imkan verir — this.contains("@") əvəzinə sadəcə contains("@") yazmaq olar.
Genişləndirmə funksiyaları əlavə parametrlər qəbul edə və istənilən tipdə dəyər qaytara bilər. Bu onları sadəcə sintaktik şəkər deyil, tam hüquqlu funksiyalar edir.
fun List<Int>.defaultIfEmpty(default: Int): List<Int> {
if (this.isEmpty()) return listOf(default)
return this
}
val populated = listOf(1, 2).defaultIfEmpty(0)
val empty = listOf<Int>().defaultIfEmpty(0)
default parametri boş siyahı üçün qaytarılan dəyəri müəyyən edir. Genişləndirmə funksiyası generic ola bilər — List
Kotlin-də genişləndirmə funksiyaları statik dispetçerləşdirmədən istifadə edir, virtual yox. Bu, adi sinif metodlarından əsas fərqdir. Hansı genişləndirmə funksiyasının çağırılacağı kompilyasiya mərhələsində dəyişənin statik tipinə görə müəyyən edilir, onun icra zamanı faktiki tipinə görə yox.
open class Animal
class Dog : Animal()
fun Animal.speak() = "Heyvan səsi"
fun Dog.speak() = "Hürmək"
fun test() {
val animal: Animal = Dog()
println(animal.speak()) // "Heyvan səsi" — statik tip Animal
val dog: Dog = Dog()
println(dog.speak()) // "Hürmək" — statik tip Dog
}
Dəyişən animal Dog nümunəsinə işarə etsə də, Animal üçün genişləndirmə funksiyası çağırılır, çünki dəyişənin statik tipi Animal-dır. Əgər speak() sinfin virtual metodu olsaydı, Dog.speak() çağırılardı. Bu xüsusiyyət genişləndirmə funksiyaları üzərində API layihələndirərkən nəzərə alınmalıdır.
Genişləndirmə funksiyaları sinif üzvü deyil — bunlar adi funksiyalardır və başqa faylda istifadə üçün import tələb edir. Kotlin iki import variantı təklif edir: funksiya adı ilə və ya adın dəyişdirilməsi ilə.
// Ada görə import
import com.example.extensions.isEmail
// Alias ilə import (konfliktləri həll etmək üçün)
import com.example.extensions.isEmail as isValidEmail
// İmportdan sonra çağırış
val valid = "test@test.com".isEmail()
Adın dəyişdirilməsi as vasitəsilə ad konfliktlərində faydalıdır — məsələn, iki kitabxana eyni tip üçün eyni adlı genişləndirmə funksiyası təqdim edərsə. Bu halda onlardan birini başqa adla import edib yeni adla çağırmaq olar.
Genişləndirmə funksiyaları müxtəlif səviyyələrdə elan edilə bilər:
| Səviyyə | Görünmə | Nümunə |
|---|---|---|
| Top-level | İmportdan sonra bütün layihə | fun String.isEmail() |
| Member extension | Sahib sinif daxilində | class A { fun B.ext() } |
| Local | Funksiya daxilində | fun test() { fun String.ext() } |
Member extension functions — genişləndirmə funksiyasının başqa sinif daxilində elan edildiyi xüsusi haldır. Bu halda genişləndirmə funksiyası daxilində həm qəbuledici (funksiyanın this-i), həm də xarici sinfin üzvləri əlçatandır.
Əgər sinfin genişləndirmə funksiyası ilə eyni imzaya malik metodu varsa, həmişə sinif üzvü çağırılır. Genişləndirmə funksiyası heç vaxt sinif metodunu ləğv etmir — bu təsadüfi ləğvlərin qarşısını almaq üçün memarlıq qərarıdır.
class User {
fun greet() = "Salam sinifdən"
}
fun User.greet() = "Hello from extension"
fun main() {
val user = User()
println(user.greet()) // "Salam sinifdən"
}
Genişləndirmə funksiyası daha sonra təyin edilsə və eyni imzaya malik olsa belə, kompilyator sinif metodunu seçəcək. Kotlin kompilyatoru belə bir vəziyyət aşkar edildikdə xəbərdarlıq göstərir. Sinif metodu mövcud olduqda genişləndirmə funksiyasını çağırmağın yeganə yolu ona adi funksiya kimi müraciət etməkdir: greet(user).
Android tərtibatında genişləndirmə funksiyaları View, Context və fraqmentlərlə iş üçün standart vasitəyə çevrilmişdir. Android KTX kitabxanası genişləndirmə funksiyaları üzərində qurulmuşdur, Android API üçün rahat sarğılar təmin edir.
// View ilə iş üçün genişləndirmə funksiyası
fun View.show() {
visibility = View.VISIBLE
}
fun View.hide() {
visibility = View.GONE
}
// Context üçün genişləndirmə funksiyası — toast
fun Context.toast(message: String) {
Toast.makeText(this, message, Toast.LENGTH_SHORT).show()
}
// DSL qurucu kimi genişləndirmə funksiyası
fun String.colorFormat(color: String): String =
"$color$this\u001b[0m"
toast() genişləndirmə funksiyası Context-dən asılı çağırışları yığcam edir: Toast.makeText(context, message, length).show() yazmaq əvəzinə context.toast("Mətn") yazmaq kifayətdir. Bu, boilerplate-i azaldır və kodu daha oxunaqlı edir.
Tez-tez verilən suallar
Xeyr, genişləndirmə funksiyaları statik dispetçerləşdirmədən istifadə edir. Əgər baza sinfi və alt sinif üçün eyni genişləndirmə funksiyası elan edilərsə, hansının çağırılacağı kompilyasiya mərhələsində dəyişənin statik tipi ilə müəyyən edilir, icra zamanı faktiki tip ilə yox.
Nullable qəbuledici tiplər üçün genişləndirmə funksiyaları elan etmək olar: fun String?.isNullOrEmail(). Belə funksiya daxilində this null ola bilər, buna görə də təhlükəsiz çağırış operatorlarından və ya açıq null yoxlamasından istifadə etmək lazımdır.
Xeyr, genişləndirmə funksiyaları statik metodlara kompilyasiya olunur. Bayt kodu səviyyəsində genişləndirmə funksiyasının çağırışı birinci parametr-qəbuledici ilə statik metod çağırışı ilə eynidir. Heç bir refleksiya və ya dinamik dispetçerləşdirmə yoxdur.
Bəli, genişləndirmə xassələri genişləndirmə funksiyaları kimi işləyir, lakin vəziyyət saxlaya bilməz — yalnız getter və setter. Məsələn: val List<Int>.sum get() = reduce(Int::plus). Onlar da getter/setter statik metodlarına kompilyasiya olunur.
Java-da StringUtils.isEmail(str) yazırsan, Kotlin-də isə str.isEmail(). Fərq təkcə sintaksisdə deyil: genişləndirmə funksiyaları IDE-də avtomatik tamamlama dəstəkləyir, çağırış zəncirlərinin oxunaqlılığını yaxşılaşdırır və IDE-yə konkret tip üçün müvafiq funksiyalar təklif etməyə imkan verir. Java-da bu imkanlar yoxdur.
Nəticə
Açar təslim mobil tətbiq hazırlayacağıq
IT Sectr 2017-ci ildən startaplar və bizneslər üçün iOS və Android tətbiqləri yaradır. Sizə məsləhət verəcəyik və ən yaxşı həlli təklif edəcəyik.
Həm də oxuyun