Путаница с пониманием лямбды и приемников

Котлин 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.

Другие вопросы по тегам