Daha yüksek sıralı işlevler çok faydalıdır ve reusability
kodu gerçekten geliştirebilirler . Ancak, bunları kullanmanın en büyük endişelerinden biri verimliliktir. Lambda ifadeleri sınıflara (genellikle anonim sınıflara) derlenir ve Java'da nesne oluşturma ağır bir işlemdir. İşlevleri satır içi yaparak tüm faydaları korurken, üst düzey işlevleri etkili bir şekilde kullanmaya devam edebiliriz.
burada satır içi işlevi resme geliyor
Bir işlev olarak işaretlendiğinde inline
, kod derleme sırasında derleyici tüm işlev çağrılarını işlevin gerçek gövdesiyle değiştirir. Ayrıca, bağımsız değişkenler olarak sağlanan lambda ifadeleri gerçek gövdeleriyle değiştirilir. İşlevler olarak değil, gerçek kod olarak ele alınacaklar.
Kısaca: - Satır içi -> çağrılmak yerine, derleme zamanında işlevin vücut koduyla değiştirilirler ...
Kotlin'de, bir işlevi başka bir işlevin parametresi olarak kullanmak (üst düzey işlevler olarak adlandırılır), Java'dakinden daha doğaldır.
Yine de lambda kullanmanın bazı dezavantajları vardır. Anonim sınıflar (ve dolayısıyla nesneler) olduklarından, belleğe ihtiyaçları vardır (ve hatta uygulamanızın genel yöntem sayısını artırabilirler). Bundan kaçınmak için yöntemlerimizi satır içi yapabiliriz.
fun notInlined(getString: () -> String?) = println(getString())
inline fun inlined(getString: () -> String?) = println(getString())
Yukarıdaki örnekten : - Bu iki işlev tam olarak aynı şeyi yapar - getString işlevinin sonucunu yazdırır. Biri satır içi ve biri değil.
Derlenmiş java kodunu kontrol ederseniz, yöntemlerin tamamen aynı olduğunu görürsünüz. Bunun nedeni, satır içi anahtar sözcüğün, derleyiciye kodu çağrı sitesine kopyalamak için bir talimat olmasıdır.
Bununla birlikte, herhangi bir işlev türünü aşağıdaki gibi başka bir işleve aktarıyorsak:
//Compile time error… Illegal usage of inline function type ftOne...
inline fun Int.doSomething(y: Int, ftOne: Int.(Int) -> Int, ftTwo: (Int) -> Int) {
//passing a function type to another function
val funOne = someFunction(ftOne)
/*...*/
}
Bunu çözmek için fonksiyonumuzu aşağıdaki gibi yeniden yazabiliriz:
inline fun Int.doSomething(y: Int, noinline ftOne: Int.(Int) -> Int, ftTwo: (Int) -> Int) {
//passing a function type to another function
val funOne = someFunction(ftOne)
/*...*/}
Aşağıdaki gibi daha yüksek dereceli bir fonksiyonumuz olduğunu varsayalım:
inline fun Int.doSomething(y: Int, noinline ftOne: Int.(Int) -> Int) {
//passing a function type to another function
val funOne = someFunction(ftOne)
/*...*/}
Burada, derleyici bize sadece bir lambda parametresi olduğunda ve onu başka bir işleve geçirdiğimizde inline anahtar kelimesini kullanmamamızı söyleyecektir. Dolayısıyla, yukarıdaki işlevi aşağıdaki gibi yeniden yazabiliriz:
fun Int.doSomething(y: Int, ftOne: Int.(Int) -> Int) {
//passing a function type to another function
val funOne = someFunction(ftOne)
/*...*/
}
Not : -Noinline anahtar sözcüğünü de kaldırmak zorundaydık çünkü yalnızca satır içi işlevler için kullanılabilir!
Bunun gibi bir işleve sahip olduğumuzu varsayalım ->
fun intercept() {
// ...
val start = SystemClock.elapsedRealtime()
val result = doSomethingWeWantToMeasure()
val duration = SystemClock.elapsedRealtime() - start
log(duration)
// ...}
Bu iyi çalışıyor ancak işlevin mantığı ölçüm koduyla kirlenmiş ve iş arkadaşlarınızın neler olup bittiğini anlamasını zorlaştırıyor.:)
Bir satır içi işlevin bu koda nasıl yardımcı olabileceği aşağıda açıklanmıştır:
fun intercept() {
// ...
val result = measure { doSomethingWeWantToMeasure() }
// ...
}
}
inline fun <T> measure(action: () -> T) {
val start = SystemClock.elapsedRealtime()
val result = action()
val duration = SystemClock.elapsedRealtime() - start
log(duration)
return result
}
Şimdi, ölçüm kodu satırlarını atlamadan, intercept () işlevinin ana amacının ne olduğunu okumaya konsantre olabilirim. Ayrıca, bu kodu istediğimiz diğer yerlerde yeniden kullanma seçeneğinden de yararlanıyoruz.
satır içi, lambda benzeri ölçüyü (myLamda) iletmek yerine bir kapanış ({...}) içinde lambda argümanı olan bir işlevi çağırmanıza izin verir
Bu ne zaman faydalıdır?
Inline anahtar sözcüğü, diğer işlevleri veya lambdaları bağımsız değişken olarak kabul eden işlevler için kullanışlıdır.
Bir işlevde satır içi anahtar sözcüğü olmadan, bu işlevin lambda bağımsız değişkeni, derleme zamanında invoke () adlı tek bir yöntemle bir İşlev arabiriminin bir örneğine dönüştürülür ve lambda'daki kod, bu İşlev örneğinde invoke () çağrısı yapılarak yürütülür. işlev gövdesinin içinde.
Bir fonksiyondaki satır içi anahtar kelimeyle, bu derleme zaman dönüşümü asla gerçekleşmez. Bunun yerine, satır içi işlevin gövdesi çağrı sitesine eklenir ve kodu, bir işlev örneği oluşturma ek yükü olmadan yürütülür.
Hmmm? Android'deki örnek ->
Diyelim ki bir aktivite yönlendirici sınıfında bir aktivite başlatmak ve bazı ekstralar uygulamak için bir fonksiyonumuz var
fun startActivity(context: Context,
activity: Class<*>,
applyExtras: (intent: Intent) -> Unit) {
val intent = Intent(context, activity)
applyExtras(intent)
context.startActivity(intent)
}
Bu işlev bir amaç oluşturur, applyExtras işlevi bağımsız değişkenini çağırarak bazı ekstralar uygular ve etkinliği başlatır.
Derlenmiş bayt koduna bakarsak ve onu Java'ya dönüştürürsek, bu şuna benzer:
void startActivity(Context context,
Class activity,
Function1 applyExtras) {
Intent intent = new Intent(context, activity);
applyExtras.invoke(intent);
context.startActivity(intent);
}
Bunu bir etkinlikteki tıklama dinleyiciden çağırdığımızı varsayalım:
override fun onClick(v: View) {
router.startActivity(this, SomeActivity::class.java) { intent ->
intent.putExtra("key1", "value1")
intent.putExtra("key2", 5)
}
}
Bu tıklama dinleyicisi için derlenmiş bayt kodu daha sonra şuna benzer:
@Override void onClick(View v) {
router.startActivity(this, SomeActivity.class, new Function1() {
@Override void invoke(Intent intent) {
intent.putExtra("key1", "value1");
intent.putExtra("key2", 5);
}
}
}
Tıklama dinleyicisi her tetiklendiğinde yeni bir Function1 örneği oluşturulur. Bu iyi çalışıyor, ancak ideal değil!
Şimdi etkinlik yönlendirici yöntemimize satır içi ekleyelim:
inline fun startActivity(context: Context,
activity: Class<*>,
applyExtras: (intent: Intent) -> Unit) {
val intent = Intent(context, activity)
applyExtras(intent)
context.startActivity(intent)
}
Tıklama dinleyici kodumuzu hiç değiştirmeden, artık bu Function1 örneğinin oluşturulmasını önleyebiliyoruz. Tıklama dinleyici kodunun Java eşdeğeri artık şuna benzer:
@Override void onClick(View v) {
Intent intent = new Intent(context, SomeActivity.class);
intent.putExtra("key1", "value1");
intent.putExtra("key2", 5);
context.startActivity(intent);
}
Bu kadar.. :)
Bir işlevi "satır içi" yapmak, temelde bir işlevin gövdesini kopyalayıp işlevin çağrı sitesine yapıştırmak anlamına gelir. Bu, derleme sırasında olur.