Kotlin'deki kapsam işlevleri, bir nesnenin bağlamında bir kod bloğu yürüten beş standart kitaplık işlevidir (let, run, with, apply, also). Nesneye erişim şekilleri (it veya this aracılığıyla) ve dönüş değeri (bağlam nesnesi veya lambda sonucu) bakımından farklılık gösterirler. Kotlin belgelerine (2026) göre, doğru kapsam işlevi seçimi, kalıp kodu %25–40 oranında azaltır. Kapsam işlevleri, nesne başlatma, yapılandırma ve dönüşümleri bildirimsel bir stilde yazmaya yardımcı olur.
Kilit noktalar
Kapsam işlevleri, Kotlin standart kitaplığına yerleşik beş işlevden (let, run, with, apply, also) oluşan bir kümedir. Her biri bir lambda alır ve lambda içindeki kodun belirli bir nesnenin bağlamında yürütülmesi için kapsamı geçici olarak değiştirir. Bu, birden çok çağrı için nesne adının tekrarlanmasını önler ve ilgili işlemleri tek bir blokta gruplandırır.
Kapsam işlevlerini ayıran iki temel özellik: bağlam nesnesine erişim şekli (this veya it aracılığıyla) ve dönüş değeri (bağlam nesnesinin kendisi veya lambda sonucu). this aracılığıyla erişim, nesneyi örtük bir alıcı yapar — yöntemler ve özellikler ön ek olmadan çağrılır. it aracılığıyla erişim, nesneyi lambda'nın açık bir parametresi olarak iletir. Nesneyi döndürmek zincirlemeye olanak tanır, sonucu döndürmek dönüştürülmüş değerin atanmasına olanak tanır.
Tarihsel olarak, kapsam işlevleri klasik Builder deseninin ve başlatma için geçici değişkenlerin yerini alarak ortaya çıkmıştır. Ayrı bir builder sınıfı oluşturmak yerine, geliştirici apply { özellik1 = ...; özellik2 = ... } yazar. Bu, kod miktarını azaltır ve başlatmayı daha okunabilir hale getirir. Kotlin ekosisteminde, kapsam işlevleri tüm çerçeve ve kitaplıklarda standart bir dil deyimi olarak kullanılır.
Doğru kapsam işlevinin seçimi iki soruyla belirlenir: nesneye erişmek için this mi yoksa it mi kullanmak istiyorsunuz ve nesnenin kendisini mi yoksa lambda sonucunu mu döndürmek istiyorsunuz. İki ikili özelliğin kombinasyonu dört olası seçenek verir ve with, genişletme olmayan tek işlev olarak özel bir konuma sahiptir.
| İşlev | Erişim | Dönüş | Genişletme? | Tipik senaryo |
|---|---|---|---|---|
| let | it | lambda sonucu | evet | Dönüşüm, null kontrolü |
| run | this | lambda sonucu | evet | Bağlamla hesaplama |
| with | this | lambda sonucu | hayır | Çağrıları gruplama |
| apply | this | bağlam nesnesi | evet | Özellik başlatma |
| also | it | bağlam nesnesi | evet | Yan etkiler, günlükleme |
Yeni bir değer döndürmeden bir nesneyi yapılandırmak için apply (this aracılığıyla erişim) veya also (it aracılığıyla erişim) kullanın. Bir nesneye dayalı olarak yeni bir değer hesaplamak için let (it aracılığıyla erişim) veya run (this aracılığıyla erişim) kullanın. Zincirleme olmadan çağrıları gruplamak için with kullanın. Bu şemayı izlemek, kodu Kotlin'e aşina diğer geliştiriciler için öngörülebilir hale getirir.
apply, bağlam nesnesini döndüren ve ona this aracılığıyla erişim sağlayan bir kapsam işlevidir. Bu, bir nesnenin özelliklerini oluşturulduktan sonra başlatmak için ideal araçtır. apply bloğu içinde, özellikler nesne adı tekrarlanmadan ayarlanabilir. Yöntem, nesnenin kendisini döndürür, böylece apply'nin zincirlere yerleştirilmesine veya başlatıcılarda kullanılmasına olanak tanır.
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
}
Listede apply, this aracılığıyla doğrudan özelliklere erişerek ServerConfig'i yapılandırır (this atlanmıştır). Apply olmadan config.host = ..., config.port = ... yazmak gerekirdi — aynı değişkene üç tekrarlayan başvuru. Nesneyi döndürmek, yapılandırma sonucunun val config'de saklanmasına olanak tanır. also, apply'nin aksine, nesneyi it aracılığıyla iletir ve yan etkiler için uygundur.
fun saveUser(user: User) {
validate(user).also { result ->
println("Doğrulama sonucu: $result")
}
val savedUser = user.also {
log("Saving user ${it.id}")
database.save(it)
}
}
Örnekte also, günlükleme için kullanılır — orijinal nesneyi döndürürken, nesneyi değiştirmeden bir yan etki (mesaj çıktısı) gerçekleştirir. Bu bir zincirdir: validate(user) User döndürür, also sonucu günlükler ve kullanıcıyı iletir. also, koleksiyonlara öğe eklemek veya dönüşüm zincirinin ortasında hata ayıklamak için de yararlıdır.
let, lambda sonucunu döndüren ve bağlamı it aracılığıyla ileten bir kapsam işlevidir. Bu, null güvenli dönüşümler için birincil işlevdir: nesne nullable ise, ?.let { } kombinasyonu bloğu yalnızca null olmayan değerler için yürütür. let ayrıca geçici değişkenlerin kapsamını sınırlamak ve bir türden diğerine map benzeri dönüşümler için de kullanılır.
fun findUser(id: Int): User?
val displayName = findUser(42)?.let { user ->
"${user.name} (${user.email})"
} ?: "Unknown user"
// koleksiyon dönüşümü ile let
val numbers = listOf("1", "2", "3")
val parsed = numbers.firstOrNull()?.let {
it.toIntOrNull()
} ?: 0
İlk örnekte let ?. aracılığıyla çağrılır — blok yalnızca findUser null olmayan bir değer döndürdüyse yürütülür. Lambda, it aracılığıyla user'ı alır (netlik için yeniden adlandırılabilir) ve biçimlendirilmiş bir dize döndürür. Kullanıcı bulunamazsa, Elvis operatörü ?: varsayılan bir değer sağlar. İkinci örnekte let, bir dizgeyi potansiyel null ile bir sayıya dönüştürür.
run, this aracılığıyla erişime sahip let'in bir benzeridir ve lambda sonucunu döndürür. run, nesne bağlamı gerektiren ancak yeni bir değer döndüren hesaplamalar için uygundur. Nesne olmadan run() çağırmak (run { ... } olarak) değişkenler için geçici bir kapsam oluşturur. with, this aracılığıyla erişime sahip bir genişletme olmayandır ve zincirleme olmadan çağrıları gruplamak için uygundur.
// bağlam odaklı hesaplama olarak run
val transformed = listOf(1, 2, 3).run {
filter { it > 1 }.map { it * 10 }
}
println(transformed) // [20, 30]
// çağrıları gruplamak için with
val info = with(StringBuilder()) {
append("Name: ")
append("Alice")
toString()
}
Örnekte, bir listede run, filtreleme ve eşlemenin sonucunu döndürür — listenin kendisini değil, dönüşümü. with, StringBuilder'ı argüman olarak alır (nokta aracılığıyla değil) ve içeride this ile çalışır: append, append, toString. with'nin sonucu info dizesidir. run ve with arasındaki seçim genellikle özneldir, ancak nesne zincirleme olmadan başka bir yerden iletildiğinde with tercih edilir.
with, bir genişletme işlevi olmaması bakımından diğer kapsam işlevlerinden ayrılır. Nesneyi ilk argüman ve lambdayı ikinci argüman olarak alır. Lambda'nın içinde nesneye this aracılığıyla erişilebilir. with, sonucu kaydetmeden nesne yöntem çağrılarını gruplamak veya birden çok özelliği okumak için geçici olarak bir bağlama “girmeniz” gerektiğinde kullanışlıdır.
val user = User("Alice", "alice@example.com", "Admin")
val summary = with(user) {
"User $name has role $role and email $email"
}
println(summary)
// UI bileşeni başlatma için with
with(TextView(context)) {
text = "Hello"
textSize = 18.0f
setTextColor(Color.BLUE)
}
İlk örnekte with, this aracılığıyla doğrudan user özelliklerine erişerek summary dizesini oluşturur. With olmadan "User ${user.name} has role ${user.role}" yazmak gerekirdi — user'ın tekrarı. İkinci örnekte with, TextView yapılandırmasını gruplar: tüm yöntemler ve özellikler tekrarlanmadan tek bir nesne üzerinde çağrılır. With'nin dezavantajı — bir genişletme olmadığı ve bağlam nesnesini döndürmediği için zincirde kullanılamaması.
Sıkça sorulan sorular
apply kullanın — nesneyi döndürür ve this aracılığıyla erişim sağlar, böylece nesne adını tekrarlamadan özellikleri ayarlayabilirsiniz. also, nesne özelliklerinden ayırt etmek için açık bir it parametresine ihtiyaç duyulduğunda uygundur.
let bağlamı it (açık parametre) aracılığıyla iletir, run — this (örtük alıcı) aracılığıyla iletir. let null kontrolleri ve dönüşümler için uygundur, run — bağlamla hesaplamalar için. Her ikisi de lambda sonucunu döndürür.
with bir genişletme değildir — nesneyi argüman olarak alır. Zincirleme gerekmediğinde çağrıları gruplamak için with kullanın. apply, nesneyi döndüren bir genişletmedir, başlatıcılarda ve builder desenlerinde kullanışlıdır.
Evet, ancak this konusunda dikkatli olun — iç içe this karışıklığa neden olur. Dış nesneye atıfta bulunurken belirsizliği önlemek için iç içe bağlamlar için açık adlarla let veya also kullanın.
Tüm kapsam işlevleri inline'dır, bu nedenle anonim sınıflardan ek yük oluşturmazlar. Aralarındaki performans farkı ihmal edilebilir düzeydedir. Seçim, hıza değil, okunabilirlik ve kurallara dayanmalıdır.
Özet
Anahtar teslim bir mobil uygulama geliştireceğiz
IT Sectr, 2017'den beri girişimler ve işletmeler için iOS ve Android uygulamaları oluşturmaktadır. Size danışmanlık yapacak ve en iyi çözümü önereceğiz.
Ayrıca okuyun