Kotlin версии 1.2.50
Я следил за некоторыми примерами из этого урока на YouTube https://thewikihow.com/video_gPH9XnvpoXE. И кое-что я понял, но все же есть некоторая путаница. Я оставил комментарии в приведенном ниже коде, где я не уверен, что происходит.
fun main(args: Array<String>) {
val javaClient = createClient {
firstName = "joe"
lastName = "bloggs"
twitter {
handle = "@joebloggs"
}
}
println(javaClient.toConsole)
}
/* Are we passing in a lambda and receiver. What will the receiver be */
private fun JavaClientBuilder.twitter(suppler: JavaTwitterBuilder.() -> Unit) {
/* We call JavaTwitterBuilder().apply(..) Will apply return the newly created object? Not sure why we have to pass the suppler in the apply */
twitter = JavaTwitterBuilder().apply(suppler).build()
}
/* Are we passing in a lambda and receiver that return nothing */
private fun createClient(suppler: JavaClientBuilder.() -> Unit): JavaClient {
val javaClientBuilder = JavaClientBuilder()
/* confusion: Not sure about this, as we are calling suppler. Just wondering is the suppler the the JavaClientBuilder that was called in the above javaClient {} lambda */
javaClientBuilder.suppler()
return javaClientBuilder.build()
}
/* I understand this, an extension function that formats and returns the string from the JavaClient object it was called on */
private val JavaClient.toConsole: String
get() =
"Created client is: ${twitter.handle} ${company.name}"

/* Are we passing in a lambda and receiver. What will the receiver be */
private fun JavaClientBuilder.twitter(suppler: JavaTwitterBuilder.() -> Unit)
У нас действительно есть приемник в этой функции, и это экземпляр JavaClientBuilder, для которого эта функция будет вызываться.
/* We call JavaTwitterBuilder().apply(..) Will apply return the newly created object? Not sure why we have to pass the suppler in the apply */
twitter = JavaTwitterBuilder().apply(suppler).build()
Чтобы понять, как работает apply(), взгляните на его исходный код (упрощенная версия):
public inline fun <T> T.apply(block: T.() -> Unit): T {
block()
return this
}
Это функция расширения, объявленная на приемнике типа T и возвращающая экземпляр T, который принимает блок - еще одну функцию расширения с приемником типа T, возвращающую Unit. Обычно он используется для замены шаблона Builder - применения настраиваемой логики инициализации к объекту. В вашем случае suppler - это блок, который содержит логику инициализации для экземпляра JavaTwitterBuilder. Код функции создает экземпляр и использует apply() с логикой в suppler для инициализации этого экземпляра.
/* Are we passing in a lambda and receiver that return nothing */
private fun createClient(suppler: JavaClientBuilder.() -> Unit): JavaClient
В данном случае у createClient() нет ресивера, это функция верхнего уровня.
/* confusion: Not sure about this, as we are calling suppler. Just wondering is the suppler the the JavaClientBuilder that was called in the above javaClient {} lambda */
javaClientBuilder.suppler()
suppler - это лямбда, в которой JavaClientBuilder является типом приемника, что позволяет нам вызывать его во вновь созданном экземпляре JavaClientBuilder.
/* I understand this, an extension function that formats and returns the string from the JavaClient object it was called on */
private val JavaClient.toConsole: String get() = "Created client is: ${twitter.handle} ${company.name}"
Верно! Небольшая поправка, это свойство расширения. У свойств могут быть собственные методы получения и установки. Это свойство определяет настраиваемый геттер, поэтому действительно, всякий раз, когда к этому свойству обращаются, он будет создавать строку с форматом, описанным кодом геттера.
Примеры чего конкретно?
Надеюсь, следующий пример поможет понять лямбда с типом получателя:
data class Person(val name: String)
fun getPrefixSafely(
prefixLength: Int,
person: Person?,
getPrefix: Person.(Int) -> String): String
{
if (person?.name?.length ?: 0 < prefixLength) return ""
return person?.getPrefix(prefixLength).orEmpty()
}
// Here is how getPrefixSafely can be called
getPrefixSafely(
prefixLength = 2,
person = Person("name"),
getPrefix = { x -> this.name.take(x) }
)
PS: Эти функциональные литералы с типами приемников аналогичны функциям расширения IMO.
@ ant2009, Что-нибудь особенное, о чем вы бы хотели поподробнее?