Kotlin Scope Fonksiyonlar
Scope fonksiyonlar kod ‘un daha anlaşılır olması amacıyla gelişirilmiş ve kod okunabilirliğini arttıran fonksiyonlardır.
Kotlin ‘de 5 adet scope fonksiyon mevcuttur.
- apply
- also
- let
- run
- with
5’i de birbirinden ayrıldığı noktaları bu yazı dizisinde incelyeceğiz.
Öncelikle Neden ihtiyaç var ? sorusuna cevap verelim.
En önemlisi kod okunabilirliği arttırdığını demiştik, hemen gösterelim. Person class ‘ı yazdık. Değer atamaları yaptık. Sonra verilerimizi güncellememiz gerekti. Örnek olarak aşağıdaki kod ‘a bakınız.. Hep person değişkeninde name, surName vs çağırarak yaptık. Hep person yazdık. Kod okunabilirliği az burada.
Bu kod daha okunabilir nasıl olur ?
Hep person yazmak vs aslında kodu biraz daha anlaşılır bir şekilde güzelleştirmemiz lazım.
val person = Person( "Ümti","köse",28,"Ankara")
person.name = "Ümit"
person.surName = person.surName.toUpperCase()
person.age.increamentAge()
person.city = "İstanbul"
print(person)
Çıktı -> Person(name=Ümit, surName=KÖSE, age=28, city=İstanbul)Daha iyi olması için scope fonksiyonlardan apply ile uygulasaydık nasıl olurdu ?
val person = Person( "Ümti","köse",28,"Ankara").apply {
name = "Ümit"
surName.toUpperCase()
age.increamentAge()
city ="İstanbul"
print(this)
}
çıktı -> Person(name=Ümit, surName=köse, age=28, city=İstanbul)
Person Class ‘ının değişkeninin ilk kodta sürekli olarak person değeri ile çağırılması biraz size de itici gelmiyor mu ? Bu kodu gören biri direk Person class ‘ıyla ilgili bişey olduğunu görebilir. Misal alertDialog kullanırken, webView kullanırken herşeyde kullanabiliriz.
Şimdi 5 tane Scope fonksiyon var, peki hangisi ne zaman kullanılacak ?
MobileTipster ‘ın android-daily-tips ‘teki görseli kullanarak özetlemek gerekirse :
Kaynak : //github.com/MobileTipsters/android-daily-tips

Ezberlemeyin, fakat resim de hep hayalinizde olsun.
Scope fonksiyonlar arasında gördüğüm 2 tane farklılık mevcut. Bunlar her fonksiyon birbirine benzemesine rağmen kullanım yerleri farklı kısaca ya return değeri değişiyor ya da üzerimizde çalıştığımız obje argument veya receiver oluyor. Eee yani ? Hadi bunlarıda inceleyelim.
This veya It (Receiver – Argument) Nedir ?
Öncelikle örneklerle kafanızda daha iyi kafanızda yer edineceğini düşünüyorum. Örnekleri her bir scope fonksiyonda anlatacağım. Yoksa çok uzun bir yazı oalcak.
Kısaca her bir fonksiyon kendi içerisinde ya it ya da this aldığını görüyoruz. Peki neye göre it veya this alıyor, altındaki mantık nedir diyorsanız aşağıdaki blog yazısını okumanızı tavsiye ediyorum. Kotlin ‘in sihirli dünyası burada aslında.
it -> let ve also ‘nun sahip olduğu yani argument ‘tir. İt argümanı this ‘e göre okunması daha kolaydır.
this -> run, with ve apply this keyword ‘ü vasıtasıyla, context objeyi işaret eder. Obje ilgili sınıf içerisinde kullanılıyormuş gibi, sınıf üyelerie erişim sağlayabiliyoruz. This keyword ‘ü yerine direk olarak yapacağımız işlemi de kullanabiliriz. Dışarıdan harici bir obje ile kullanıyorsak this keyword’ü ayırt edici olmaktadır.
Return / dönüş değeri ne peki ?
Scope fonksiyonlar Yukarıdaki resimdeki gibi 2 farklı değer döndürüyor.
Ya context objesi ya da lambda sonucu.
Peki Ne neyi döndürüyor ?
Context Objesi : Apply ve Also direk olarak nesneyi döndürüyorlar. Yani context objesi.
Lambda Sonucu : Direk olarak ilgili nesne içerisinde işlem yapma ya da yeni nesneyi döndürme görevini görür.
Örnek olarak :
data class Person(
var name:String,
var surName: String,
var age: Int
)
main(){
val person = Person("Ümit", "köse",12)
person.name="Ünit"
person.surName = "KÖSE"
person.age = 26
val person1 = with(person){
name = "Ümit"
surName = "KÖSE"
age = 27
}
print(person1)
çıktı --> unit iken
val person1 = person.apply{
name = "Ümit"
surName = "KÖSE"
age = 27
}
print(person1)
çıktı -> Person(name=Ümit, surName=KÖSE, age=27)
}Kafanız Karıştı Değil mi ? Hadi Hepsinin üstünden geçelim.. örneklerle daha iyi anlayacağımıza eminim.
LET :
Let ‘in tablosu aşağıdadır. Ana görevi null kontrolü yapmaktır diyebiliriz.
| Function | Obje tipi | Geri dönüş değeri | Extension fonksiyon mu? |
| let | it | Lambda Fonk. | Evet |
val str: String? = "Hello"
//processNonNullString(str) // derleme hatası: str null olabilir.
val length = str?.let {
println("let() called on $it")
processNonNullString(it) // OK: 'it', '?.let { }' içerisinde null değildir.
it.length
}
Kod okunabilirliğini arttırmak için sınırlı bir scope içerisinde local değişkenlerini let ile tanımlayabiliyoruz. Fakat siz yine de direk olarak null kontrolü yapmak için kullanın.
/* Let olmadan */val harf = charArrayOf('A', 'B', 'C', 'D', 'E')
val harfFilter = harf.filter {
it > 'C'
}
println(harfFilter)
/* let hali
* -> Context nesnesini geri döndürüyor..
* nesne üzerinde farklı işlemler yapılıp geri değer döndürmek istendiğinde let kullanılabiliyor.
* */
val harfFilterWithLet = harf.filter {
it > 'C'
}.let {
it[0]
}
println(harfFilterWithLet)
Apply :
Apply için 3 soruya cevap verelim ve nerelerde kullanılması gerektiğini söyleyelim.
| Function | Obje tipi | Geri dönüş değeri | Extension fonksiyon mu? |
| apply | this | Context Object | Evet |
Apply’i, değer dönmeyen, öncelikli hedefi objenin üyeleri için değer atama işlemi yapan kod blokları için kullanabilirsiniz. Örneği :
val person = Person().apply {
name = "Ümit"
surName.toUpperCase()
age.increamentAge()
city ="İstanbul"
print(this)
}
çıktı -> Person(name=Ümit, surName=köse, age=28, city=İstanbul)
Apply manifestosu : apply the following assignments to the object.
“Aşağıdaki atamaları objeye uygulayın.” şeklinde okunabilir.
Also :
Also için 3 soruya cevap verelim ve nerelerde kullanılması gerektiğini söyleyelim.
Function | Obje tipi | Geri dönüş değeri | Extension fonksiyon mu? |
| also | it | Context Object | Evet |
Also’u, objeyi değişime uğratmadan, loglama, debug gibi olaylar için kullanabiliriz. Örnek :
val harfFilterWithLet = harf.filter {
it > 'C'
}.also {
println("İlk Değer : ${it[0]}")
}
println(harfFilterWithLet)Run :
Run’ın en başta belirtildiği gibi 2 kullanım şekli vardır. Aşağıda 2 kullanım şeklini de inceleyelim.
1. kullanım şekli aşağıdadır.
| Function | Obje tipi | Geri dönüş değeri | Extension fonksiyon mu? |
| run | this | Lambda Fonk. | Evet |
val service = MultiportService("//example.kotlinlang.org", 80)
val result = service.run {
port = 8080
query(prepareRequest() + " to port $port")
}
// the same code written with let() function:
val letResult = service.let {
it.port = 8080
it.query(it.prepareRequest() + " to port ${it.port}")
}run(), bu kullanımında let() ile aynı şeyi yapar. Farklı oldukları kısım aldıkları parametredir. run, this parametresini; let ise it parametresini alır.
run(), lambda ifadeniz hem obje yaratmayı hem de return edilecek değerin hesaplanması gerektiğinde kullanılabilir.
2. kullanım şekli aşağıdadır.
| Function | Obje tipi | Geri dönüş değeri | Extension fonksiyon mu? |
| run | – | Lambda Fonk. | Hayır: run{…} diyerek çağırılır. |
val hexNumberRegex = run {
val digits = "0-9"
val hexDigits = "A-Fa-f"
val sign = "+-"
Regex("[$sign]?[$digits$hexDigits]+")
}
for (match in hexNumberRegex.findAll("+1234 -FFFF not-a-number")) {
println(match.value)
}run scope fonksiyonun 2. kullanımı da yukarıda ki gibi non-extension fonksiyon kullanımıdır. non-extension olan run, farklı kod satırlarının bir arada çalıştırılması gerektiğinde kullanılabilir.
With :
With için 3 soruya cevap verelim ve nerelerde kullanıldığını inceleyelim.
| Function | Obje tipi | Geri dönüş değeri | Extension fonksiyon mu? |
| with | this | Lambda fonk. | Hayır: Argüman olarak context objesini alır. |
With çağrıları; “Bu object ile, aşağıdakileri gerçekleştir.” şeklinde okunabilir.
with this object, do the following
With lambda sonucu sağlamaksızın, ilgili objeler üzerinde fonksiyonları çağırmak için kullanılabilir.
val sayi = mutableListOf(1,2,3)
with(sayi) {
println("'with ile argument çağırımı -> $this")
println("Size : $size ")
}Özetle :
Kotlin ile kod yazdık ve kodu daha okunabilir, tekrarlamayan şekilde yazmak istiyoruz. Normal kullanım yerine scope fonksiyonlar ile bunu gerçekleştirebiliyoruz. Burada dikkat etmemiz gereken genel kullanımları ile (Örn. let ile null, apply ile değişken atama vs) kullanmaya önem göstermemiz. Dikkat edeceğiniz bir nokta da scope fonksiyonları bir değişkene atayacak mısınız ? Atamayacak mısınız? Buna göre de ilgiili scope fonksiyonu seçebilmeniz önemlidir.(Return değeri -> apply ve also ile değişkene atama yapabiliriz.)


Scope fonksiyonlar ile ilgili söyleyeceklerim bu kadardır. Umarım beğenirsiniz ve faydalı bir yazı olmuştur.
Paylaşmayı unutmazsanız sevinirim 🙂
Kaynakça :
kotlin days -> //github.com/MobileTipsters/android-daily-tips
//proandroiddev.com/kotlin-scope-functions-made-simple-c59b97a04ca2
//kotlinlang.org/docs/reference/scope-functions.html
//kotlinexpertise.com/coping-with-kotlins-scope-functions/
//blog.mindorks.com/using-scoped-functions-in-kotlin-let-run-with-also-apply




