Kotlin-də scope functions standart kitabxananın beş funksiyasıdır (let, run, with, apply, also) — onlar obyekt kontekstində kod blokunu icra edirlər. Onlar obyektə giriş üsulu (it və ya this vasitəsilə) və qaytarılan dəyər (kontekst obyekti və ya lambda nəticəsi) ilə fərqlənirlər. Kotlin sənədlərinə (2026) görə, düzgün scope function seçimi şablon kodu 25–40% azaldır. Scope functions obyektlərin inisializasiyası, konfiqurasiyası və transformasiyasını deklarativ üslubda yazmağa kömək edir.
Əsas məqamlar
Scope functions (görünmə dairəsi funksiyaları) — Kotlin standart kitabxanasına daxil edilmiş beş funksiyadan ibarət dəstdir (let, run, with, apply, also). Onların hər biri lambda qəbul edir və müvəqqəti olaraq görünmə dairəsini dəyişir ki, lambda daxilində kod konkret obyektin kontekstində icra olunsun. Bu, çoxsaylı çağırışlarda obyekt adının təkrarlanmasından qurtarır və əlaqəli əməliyyatları bir blokda qruplaşdırır.
Scope functions-ları fərqləndirən iki əsas xüsusiyyət var: kontekst obyektinə giriş üsulu (this və ya it vasitəsilə) və qaytarılan dəyər (kontekst obyekti və ya lambda nəticəsi). This vasitəsilə giriş obyekti qeyri-aşkar qəbul edən edir — metodlar və xassələr prefiks olmadan çağırılır. It vasitəsilə giriş obyekti lambdanın aşkar parametri kimi ötürür. Obyektin qaytarılması zəncirvari çağırışlar qurmağa, nəticənin qaytarılması isə çevrilmiş dəyəri mənimsətməyə imkan verir.
Tarixən scope functions klassik Builder nümunəsinin və inisializasiya üçün müvəqqəti dəyişənlərin əvəzedicisi kimi meydana çıxmışdır. Ayrıca builder sinfi yaratmaq əvəzinə, proqramçı apply { xassə1 = ...; xassə2 = ... } yazır. Bu, kodun həcmini azaldır və inisializasiyanı daha oxunaqlı edir. Kotlin ekosistemində scope functions bütün freymvorklarda və kitabxanalarda dilin standart idioması kimi istifadə olunur.
Düzgün scope function seçimi iki sualla müəyyən edilir: obyektə giriş üçün this və ya it istifadə etmək istəyirsinizmi və obyektin özünü və ya lambda nəticəsini qaytarmaq istəyirsinizmi. İki ikili xüsusiyyətin kombinasiyası dörd mümkün variant verir, with isə genişləndirmə olmayan yeganə funksiya kimi xüsusi yer tutur.
| Funksiya | Giriş | Qaytarır | Genişləndirmə? | Tipik ssenari |
|---|---|---|---|---|
| let | it | lambda nəticəsi | bəli | Transformasiya, null yoxlaması |
| run | this | lambda nəticəsi | bəli | Kontekst ilə hesablama |
| with | this | lambda nəticəsi | xeyr | Çağırışların qruplaşdırılması |
| apply | this | kontekst obyekti | bəli | Xassələrin inisializasiyası |
| also | it | kontekst obyekti | bəli | Yan təsirlər, loqlama |
Yeni dəyər qaytarmadan obyektin konfiqurasiyası üçün apply (this vasitəsilə giriş) və ya also (it vasitəsilə giriş) istifadə edin. Obyekt əsasında yeni dəyər hesablamaq üçün let (it vasitəsilə giriş) və ya run (this vasitəsilə giriş) istifadə edin. Zəncirvari çağırış olmadan çağırışları qruplaşdırmaq üçün with istifadə edin. Bu sxemə riayət etmək kodu Kotlin bilən digər proqramçılar üçün proqnozlaşdırıla bilən edir.
apply — kontekst obyektini qaytaran və ona this vasitəsilə giriş təmin edən scope function-dur. Bu, obyekt yaradıldıqdan sonra onun xassələrini inisializasiya etmək üçün ideal vasitədir. apply bloku daxilində xassələri obyekt adını təkrarlamadan təyin etmək olar. Metod obyektin özünü qaytarır ki, bu da apply-ni zəncirlərə daxil etməyə və ya inisializatorlarda istifadə etməyə imkan verir.
data class ServerConfig(
var host: String = "localhost",
var port: Int = 8080,
var useTls: Boolean = false
)
val config = ServerConfig().apply {
host = "api.example.com"
port = 443
useTls = true
}
Nümunədə apply ServerConfig-i konfiqurasiya edir, xassələrə birbaşa this vasitəsilə müraciət edir (this buraxılıb). Apply olmadan config.host = ..., config.port = ... yazmaq lazım gələrdi — eyni dəyişənə üç təkrarlanan müraciət. Obyektin qaytarılması konfiqurasiya nəticəsini val config-də saxlamağa imkan verir. also, apply-dən fərqli olaraq, obyekti it vasitəsilə ötürür və yan təsirlər üçün uyğundur.
fun saveUser(user: User) {
validate(user).also { result ->
println("Yoxlama nəticəsi: $result")
}
val savedUser = user.also {
log("Saving user ${it.id}")
database.save(it)
}
}
Nümunədə also loqlama üçün istifadə olunur — orijinal obyekti qaytararaq, obyekti dəyişmədən yan təsir (mesaj çap etmə) icra edir. Bu zəncirdir: validate(user) User qaytarır, also nəticəni loqlayır və istifadəçini irəli ötürür. also həmçinin kolleksiyalara elementlər əlavə etmək və ya transformasiya zəncirinin ortasında debug etmək üçün faydalıdır.
let — lambda nəticəsini qaytaran və konteksti it vasitəsilə ötürən scope function-dur. Bu, null-təhlükəsiz transformasiyalar üçün əsas funksiyadır: obyekt nullable-dırsa, ?.let { } kombinasiyası bloku yalnız qeyri-null dəyərdə icra edir. let həmçinin müvəqqəti dəyişənlərin görünmə dairəsini məhdudlaşdırmaq və bir tipi digərinə map-bənzər transformasiya etmək üçün istifadə olunur.
fun findUser(id: Int): User?
val displayName = findUser(42)?.let { user ->
"${user.name} (${user.email})"
} ?: "Unknown user"
// let kolleksiya transformasiyası ilə
val numbers = listOf("1", "2", "3")
val parsed = numbers.firstOrNull()?.let {
it.toIntOrNull()
} ?: 0
Birinci nümunədə let ?. vasitəsilə çağırılır — blok yalnız findUser null qaytarmadıqda icra olunur. Lambda user-i it vasitəsilə qəbul edir (aydınlıq üçün adlandırmaq olar) və formatlanmış sətri qaytarır. İstifadəçi tapılmadıqda — Elvis operatoru ?: default dəyər verir. İkinci nümunədə let sətri potensial null ilə rəqəmə çevirir.
run — this vasitəsilə girişi olan, lambda nəticəsini qaytaran let analoqudur. run obyekt konteksti tələb olunan, lakin yeni dəyər qaytarılan hesablamalar üçün əlverişlidir. Obyektsiz run() çağırışı (run { ... }) dəyişənlər üçün müvəqqəti görünmə dairəsi yaradır. with — this vasitəsilə girişi olan, lakin genişləndirmə olmayan, zəncirvari çağırış olmadan çağırışları qruplaşdırmaq üçün uyğun funksiyadır.
// run kontekstli hesablama kimi
val transformed = listOf(1, 2, 3).run {
filter { it > 1 }.map { it * 10 }
}
println(transformed) // [20, 30]
// with çağırışları qruplaşdırmaq üçün
val info = with(StringBuilder()) {
append("Name: ")
append("Alice")
toString()
}
Nümunədə siyahıda run filtrasiya və map-in nəticəsini qaytarır — siyahının özünü yox, transformasiyanı. with StringBuilder-i arqument kimi qəbul edir (nöqtə ilə deyil) və daxildə this ilə işləyir: append, append, toString. with-in nəticəsi — info sətri. run və with arasında seçim çox vaxt subyektivdir, lakin with obyekt başqa yerdən zəncirvari çağırış olmadan ötürüldükdə daha üstündür.
with digər scope functions-lardan onunla fərqlənir ki, genişləndirmə funksiyası deyil. O, obyekti birinci arqument, lambdanı isə ikinci arqument kimi qəbul edir. Lambda daxilində obyekt this vasitəsilə əlçatandır. with nəticəni saxlamadan obyektin metod çağırışlarını qruplaşdırmaq və ya bir neçə xassəni oxumaq üçün müvəqqəti kontekstə “daxil olmaq” üçün əlverişlidir.
val user = User("Alice", "alice@example.com", "Admin")
val summary = with(user) {
"User $name has role $role and email $email"
}
println(summary)
// with UI komponentinin inisializasiyası üçün
with(TextView(context)) {
text = "Hello"
textSize = 18.0f
setTextColor(Color.BLUE)
}
Birinci nümunədə with summary sətrini formalaşdırır, user xassələrinə birbaşa this vasitəsilə müraciət edir. With olmadan “User ${user.name} has role ${user.role}” yazmaq lazım gələrdi — user-in çoxsaylı təkrarlanması. İkinci nümunədə with TextView-in konfiqurasiyasını qruplaşdırır: bütün metodlar və xassələr təkrarlanmadan bir obyektdə çağırılır. With-in çatışmazlığı — zəncirdə istifadə edilə bilməməsi, çünki genişləndirmə deyil və kontekst obyektini qaytarmır.
Tez-tez verilən suallar
apply istifadə edin — o, obyekti qaytarır və this vasitəsilə giriş təmin edir, xassələri obyekt adını təkrarlamadan təyin etməyə imkan verir. also obyektin xassələrindən fərqləndirmək üçün aşkar it parametri lazım olduqda uyğundur.
let konteksti it vasitəsilə (aşkar parametr), run isə this vasitəsilə (qeyri-aşkar qəbul edən) ötürür. let null yoxlamaları və transformasiyalar üçün, run isə kontekstli hesablamalar üçün əlverişlidir. Hər ikisi lambda nəticəsini qaytarır.
with genişləndirmə deyil — obyekti arqument kimi qəbul edir. Zəncir lazım olmadıqda çağırışları qruplaşdırmaq üçün with istifadə edin. apply — obyekti qaytaran genişləndirmə, inisializatorlarda və builder nümunələrində əlverişlidir.
Bəli, lakin this ilə diqqətli olun — iç-içə this-lər qarışıqlıq yaradır. İç-içə kontekstlər üçün aşkar adlarla let və ya also istifadə edin ki, xarici obyektə müraciətdə qeyri-müəyyənlik olmasın.
Bütün scope functions inline-dır, ona görə də anonim siniflər üçün əlavə yük yaratmır. Onlar arasında məhsuldarlıq fərqi cüzidir. Seçim sürətə deyil, oxunaqlılığa və konvensiyalara əsaslanmalıdır.
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