Çalıştırılan her işlev için iyi bir örnek olmasını diliyorum, izin ver, uygula, ayrıca,
Bu makaleyi okudum ama hala bir örnek yok
Çalıştırılan her işlev için iyi bir örnek olmasını diliyorum, izin ver, uygula, ayrıca,
Bu makaleyi okudum ama hala bir örnek yok
Yanıtlar:
Tüm bu işlevler, mevcut işlevin / değişkenin kapsamını değiştirmek için kullanılır. Birbirine ait olan şeyleri tek bir yerde tutmak için kullanılırlar (çoğunlukla ilklendirmeler).
İşte bazı örnekler:
run
- istediğiniz her şeyi döndürür ve üzerinde kullanıldığı değişkeni yeniden kapsar this
val password: Password = PasswordGenerator().run {
seed = "someString"
hash = {s -> someHash(s)}
hashRepetitions = 1000
generate()
}
Şifre üreteci artık rescoped edilir this
ve bu yüzden ayarlayabilirsiniz seed
, hash
ve hashRepetitions
bir değişken kullanmadan.
generate()
bir örnek döndürecektir Password
.
apply
benzer, ancak geri dönecek this
:
val generator = PasswordGenerator().apply {
seed = "someString"
hash = {s -> someHash(s)}
hashRepetitions = 1000
}
val pasword = generator.generate()
Bu, özellikle Oluşturucu modelinin yerine geçmesi için ve belirli yapılandırmaları yeniden kullanmak istiyorsanız yararlıdır.
let
- çoğunlukla boş denetimlerden kaçınmak için kullanılır, ancak bunun yerine de kullanılabilir run
. Aradaki fark, bu this
hala öncekiyle aynı olacak ve yeniden kapsamlı değişkene şunu kullanarak erişeceksiniz it
:
val fruitBasket = ...
apple?.let {
println("adding a ${it.color} apple!")
fruitBasket.add(it)
}
Yukarıdaki kod, elmayı yalnızca boş değilse sepete ekleyecektir. Ayrıca it
artık isteğe bağlı olmadığına dikkat edin , bu nedenle burada bir NullPointerException ile karşılaşmayacaksınız (aka. ?.
Özniteliklerine erişmek için kullanmanıza gerek yoktur )
also
- kullanmak istediğinizde apply
, ancak gölgelemek istemediğinizde kullanınthis
class FruitBasket {
private var weight = 0
fun addFrom(appleTree: AppleTree) {
val apple = appleTree.pick().also { apple ->
this.weight += apple.weight
add(apple)
}
...
}
...
fun add(fruit: Fruit) = ...
}
apply
Burada kullanmak gölge olur this
, böylece meyve sepetine değilthis.weight
elmaya atıfta bulunur .
Not: Blogumdaki örnekleri utanmadan aldım
Buraya benzer birkaç makale daha var ve burada bir göz atmaya değer.
Sanırım, birkaç satırda daha kısa, daha özlü bir yere ihtiyacınız olduğunda ve dallanma veya koşullu ifade kontrolünden kaçınmak için (boş değilse, o zaman bunu yapın).
Bu basit tabloyu seviyorum, bu yüzden buraya bağladım. Sen onu görebilirsiniz bu Sebastiano Gottardo tarafından yazılmış olarak.
Lütfen aşağıdaki açıklamama eşlik eden tabloya da bakınız.
Bu işlevleri çağırdığınızda kod bloğunuzun içinde bir rol oynama yolu olarak düşünüyorum + kendinizi geri isteyip istemediğiniz (işlevleri zincirlemek veya sonuç değişkenine ayarlamak, vb.).
Yukarıda düşündüğüm şey bu.
Burada hepsi için örnekler görelim
1.) myComputer.apply { }
ana aktör olarak hareket etmek istediğiniz (bilgisayar olduğunuzu düşünmek istediğiniz) ve kendinizi geri istediğiniz (bilgisayar) istediğiniz anlamına gelir, böylece yapabilirsiniz
var crashedComputer = myComputer.apply {
// you're the computer, you yourself install the apps
// note: installFancyApps is one of methods of computer
installFancyApps()
}.crash()
Evet, siz sadece uygulamaları yükleyin, kendinizi kilitleyin ve başkalarının görmesine ve onunla bir şeyler yapmasına izin vermek için kendinizi referans olarak kurtardınız.
2.) bilgisayar olmadığındanmyComputer.also {}
tamamen emin olduğun anlamına gelir , onunla bir şeyler yapmak isteyen ve aynı zamanda geri dönen bir sonuç olarak bilgisayar isteyen bir yabancısın.
var crashedComputer = myComputer.also {
// now your grandpa does something with it
myGrandpa.installVirusOn(it)
}.crash()
3.) with(myComputer) { }
Sen ana aktör (bilgisayar) anlamına gelir ve sen yok bir sonuç arkasında olarak kendinizi istiyorum.
with(myComputer) {
// you're the computer, you yourself install the apps
installFancyApps()
}
4.) myComputer.run { }
Sen ana aktör (bilgisayar) anlamına gelir ve sen yok bir sonuç arkasında olarak kendinizi istiyorum.
myComputer.run {
// you're the computer, you yourself install the apps
installFancyApps()
}
ancak , aşağıdaki gibi with { }
zincirleme çağrı yapabilmeniz çok ince bir anlamda farklırun { }
myComputer.run {
installFancyApps()
}.run {
// computer object isn't passed through here. So you cannot call installFancyApps() here again.
println("woop!")
}
Bunun nedeni run {}
, uzantı işlevidir, ancak with { }
değildir. Böylece aradığınız run { }
ve this
kod bloğunun içinde arayan türü nesneye yansıtılır. Görebilirsiniz bu arasındaki fark için mükemmel bir açıklama run {}
ve with {}
.
5.) myComputer.let { }
, bilgisayara bakan ve bilgisayar örneğinin size geri dönmesini umursamadan bu konuda bir şeyler yapmak isteyen yabancı olduğunuz anlamına gelir.
myComputer.let {
myGrandpa.installVirusOn(it)
}
Ben bakmak eğilimindedir also
ve let
dışında, harici bir şey olarak. Bu iki kelimeyi her söylediğinizde, sanki bir şey üzerinde harekete geçmeye çalışıyorsunuz. let
bu bilgisayara virüs yükleyin ve also
çökertin. Yani bu, aktör olup olmadığınız kısmının altını çiziyor.
Sonuç kısmı için, açıkça orada. also
bunun da başka bir şey olduğunu ifade eder, böylece nesnenin kendisinin kullanılabilirliğini hala korursunuz. Böylece onu sonuç olarak döndürür.
Diğer her şey ile ilişkilendirilir this
. Ek olarak run/with
, nesnenin geri dönüşüyle ilgilenmediği açık. Artık hepsini ayırt edebilirsiniz.
Bazen% 100 programlama / mantık temelli örneklerden uzaklaştığımızda, bir şeyleri kavramsallaştırmak için daha iyi bir konumda olduğumuzu düşünüyorum. Ama bu doğru :)
let, ayrıca, apply, takeIf, takeUnless, Kotlin'deki uzantı işlevleridir.
Bu işlevi anlamak için Kotlin'deki Uzantı işlevlerini ve Lambda işlevlerini anlamanız gerekir .
Uzatma İşlevi:
Uzantı işlevini kullanarak, bir sınıfı miras almadan bir sınıf için bir işlev oluşturabiliriz.
C # ve Gosu'ya benzer şekilde Kotlin, sınıftan miras almak veya Dekoratör gibi herhangi bir tasarım kalıbı kullanmak zorunda kalmadan bir sınıfı yeni işlevlerle genişletme yeteneği sağlar. Bu, uzantılar adı verilen özel bildirimler aracılığıyla yapılır. Kotlin, uzantı işlevlerini ve uzantı özelliklerini destekler.
Yani, içinde sadece sayı olup olmadığını bulmak için String
, String
sınıfı miras almadan aşağıdaki gibi bir yöntem oluşturabilirsiniz .
fun String.isNumber(): Boolean = this.matches("[0-9]+".toRegex())
yukarıdaki uzantı işlevini şu şekilde kullanabilirsiniz ,
val phoneNumber = "8899665544"
println(phoneNumber.isNumber)
hangi baskılar true
.
Lambda İşlevleri:
Lambda işlevleri, Java'daki Arabirim gibidir. Ancak Kotlin'de lambda fonksiyonları, fonksiyonlarda parametre olarak geçirilebilir.
Misal:
fun String.isNumber(block: () -> Unit): Boolean {
return if (this.matches("[0-9]+".toRegex())) {
block()
true
} else false
}
Gördüğünüz gibi, blok bir lambda fonksiyonudur ve bir parametre olarak aktarılır. Yukarıdaki işlevi şu şekilde kullanabilirsiniz,
val phoneNumber = "8899665544"
println(phoneNumber.isNumber {
println("Block executed")
})
Yukarıdaki işlev şu şekilde yazdırılacaktır,
Block executed
true
Umarım artık Uzantı işlevleri ve Lambda işlevleri hakkında bir fikriniz vardır. Şimdi Eklenti işlevlerine tek tek gidebiliriz.
İzin Vermek
public inline fun <T, R> T.let(block: (T) -> R): R = block(this)
Yukarıdaki işlevde kullanılan iki Tip T ve R.
T.let
T
String sınıfı gibi herhangi bir nesne olabilir. böylece bu işlevi herhangi bir nesneyle çalıştırabilirsiniz.
block: (T) -> R
Let parametresinde yukarıdaki lambda fonksiyonunu görebilirsiniz. Ayrıca, çağrılan nesne, işlevin bir parametresi olarak iletilir. Böylece, işlevin içinde çağıran sınıf nesnesini kullanabilirsiniz. sonra R
(başka bir nesne) döndürür .
Misal:
val phoneNumber = "8899665544"
val numberAndCount: Pair<Int, Int> = phoneNumber.let { it.toInt() to it.count() }
Yukarıdaki örnekte, String'i lambda fonksiyonunun bir parametresi olarak alalım ve karşılığında Pair döndürür.
Aynı şekilde, diğer uzantı işlevi de çalışır.
Ayrıca
public inline fun <T> T.also(block: (T) -> Unit): T { block(this); return this }
extension function also
, çağırma sınıfını bir lambda fonksiyon parametresi olarak alır ve hiçbir şey döndürmez.
Misal:
val phoneNumber = "8899665544"
phoneNumber.also { number ->
println(number.contains("8"))
println(number.length)
}
uygulamak
public inline fun <T> T.apply(block: T.() -> Unit): T { block(); return this }
Aynı şekilde, ancak aynı çağırma nesnesi işlev olarak iletilir, böylece işlevleri ve diğer özellikleri, onu veya parametre adını çağırmadan kullanabilirsiniz.
Misal:
val phoneNumber = "8899665544"
phoneNumber.apply {
println(contains("8"))
println(length)
}
Yukarıdaki örnekte, lambda işlevi içinde doğrudan çağrılan String sınıfının işlevlerini görebilirsiniz.
takeIf
public inline fun <T> T.takeIf(predicate: (T) -> Boolean): T? = if (predicate(this)) this else null
Misal:
val phoneNumber = "8899665544"
val number = phoneNumber.takeIf { it.matches("[0-9]+".toRegex()) }
Yukarıdaki örnekte number
, phoneNumber
yalnızca regex
. Aksi takdirde, olacaktır null
.
takeUnless
public inline fun <T> T.takeUnless(predicate: (T) -> Boolean): T? = if (!predicate(this)) this else null
TakeIf'in tersidir.
Misal:
val phoneNumber = "8899665544"
val number = phoneNumber.takeUnless { it.matches("[0-9]+".toRegex()) }
number
bir dizi olacak phoneNumber
değil eşleşmesi durumunda regex
. Aksi takdirde, olacaktır null
.
Burada faydalı olan benzer cevapları kotlin'de de görebilirsiniz, apply, let, use, takeIf ve takeUnless arasındaki farkı Kotlin'de de görebilirsiniz.
phoneNumber. takeUnless{}
yerine demek istediniz phoneNumber. takeIf{}
.
6 farklı kapsam belirleme işlevi vardır:
Farklılıkları göstermek için aşağıdaki görsel bir not hazırladım:
data class Citizen(var name: String, var age: Int, var residence: String)
Karar ihtiyaçlarınıza bağlıdır. Projenizde veya ekibinizde kullanılan belirli kurallara göre işlevleri seçebilmeniz için farklı işlevlerin kullanım durumları çakışır.
Kapsam işlevleri, kodu daha özlü hale getirmenin bir yolu olsa da, onları aşırı kullanmaktan kaçının: Kod okunabilirliğini azaltabilir ve hatalara yol açabilir. Kapsam işlevlerini iç içe yerleştirmekten kaçının ve bunları zincirlerken dikkatli olun: mevcut bağlam nesnesi ve bunun veya bunun değeri hakkında kafa karıştırmak kolaydır.
Https://medium.com/@elye.project/mastering-kotlin-standard-functions-run-with-let-also-and-apply-9cd334b0ef84 adresinden hangisinin kullanılacağına karar vermek için başka bir şema.
Bazı sözleşmeler aşağıdaki gibidir:
Günlüğe kaydetmek veya hata ayıklama bilgilerini yazdırmak gibi nesneyi değiştirmeyen ek eylemler için de kullanın .
val numbers = mutableListOf("one", "two", "three")
numbers
.also { println("The list elements before adding new one: $it") }
.add("four")
İçin ortak durum geçerlidir nesne yapılandırmasıdır.
val adam = Person("Adam").apply {
age = 32
city = "London"
}
println(adam)
Gölgelendirmeye ihtiyacınız varsa çalıştırmayı kullanın
fun test() {
var mood = "I am sad"
run {
val mood = "I am happy"
println(mood) // I am happy
}
println(mood) // I am sad
}
Alıcı nesnenin kendisini iade etmeniz gerekiyorsa, uygula veya ayrıca
Tecrübelerime göre, bu tür işlevler performans farkı olmayan satır içi sözdizimsel şeker olduğundan, her zaman lamda en az miktarda kod yazmayı gerektireni seçmelisiniz.
Bunu yapmak için, önce lambda'nın sonucunu ( run
/ seçin let
) veya nesnenin kendisini ( apply
/ seçin) döndürmesini isteyip istemediğinizi belirleyin also
; daha sonra çoğu durumda, lambda tek bir ifade olduğunda, bu ifade ile aynı blok fonksiyon tipine sahip olanları seçin, çünkü bir alıcı ifadesi this
olduğu zaman, bir parametre ifadesi it
olduğu zaman , şundan daha kısa olabilir this
:
val a: Type = ...
fun Type.receiverFunction(...): ReturnType { ... }
a.run/*apply*/ { receiverFunction(...) } // shorter because "this" can be omitted
a.let/*also*/ { it.receiverFunction(...) } // longer
fun parameterFunction(parameter: Type, ...): ReturnType { ... }
a.run/*apply*/ { parameterFunction(this, ...) } // longer
a.let/*also*/ { parameterFunction(it, ...) } // shorter because "it" is shorter than "this"
Bununla birlikte, lambda bunların bir karışımından oluştuğunda, bağlama daha uygun olanı seçmek veya kendinizi daha rahat hissetmek size kalmıştır.
Ayrıca, yapısöküm gerektiğinde parametre blok fonksiyonuna sahip olanları kullanın:
val pair: Pair<TypeA, TypeB> = ...
pair.run/*apply*/ {
val (first, second) = this
...
} // longer
pair.let/*also*/ { (first, second) -> ... } // shorter
JetBrains'in Java Geliştiricileri için Coursera Kotlin hakkındaki resmi Kotlin kursundaki tüm bu işlevler arasında kısa bir karşılaştırma :