Путаница с пониманием лямбды и приемников
Котлин 1.2.50
Я следил за некоторыми примерами из этого руководства на YouTube https://www.youtube.com/watch?v=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}"
Спасибо заранее,
2 ответа
/* Проходим ли мы в лямбду и ресивер. Каким будет получатель */
личное развлечение JavaClientBuilder.twitter(suppler: JavaTwitterBuilder.() -> Unit)
У нас действительно есть получатель в этой функции, и это пример JavaClientBuilder
что эта функция будет вызываться.
/* Мы вызываем JavaTwitterBuilder(). Apply(..) Будет ли применяться возврат вновь созданного объекта? Не уверен, почему мы должны передать Suppler в заявке */
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
инициализировать этот экземпляр.
/* Мы передаем лямбду и получатель, которые ничего не возвращают */
личное развлечение createClient(Suppler: JavaClientBuilder.() -> Unit): JavaClient
В этом случае, createClient()
нет приемника, это функция верхнего уровня.
/* путаница: не уверен насчет этого, так как мы называем Suppler. Просто интересно, является ли сторонник JavaClientBuilder, который был вызван в вышеупомянутом javaClient {} lambda */
javaClientBuilder.suppler ()
suppler
это лямбда с JavaClientBuilder
являющийся типом получателя, который позволяет нам вызывать его на только что созданном экземпляре JavaClientBuilder
,
/* Я так понимаю, функция расширения, которая форматирует и возвращает строку из объекта JavaClient, для которого она была вызвана */
private val JavaClient.toConsole: String get () = "Создан клиент: ${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.