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

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}"
Сортировка hashmap по значениям
Сортировка hashmap по значениям
На Leetcode я решал задачу с хэшмапой и подумал, что мне нужно отсортировать хэшмапу по значениям.
6
0
242
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

/* 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}"

Верно! Небольшая поправка, это свойство расширения. У свойств могут быть собственные методы получения и установки. Это свойство определяет настраиваемый геттер, поэтому действительно, всякий раз, когда к этому свойству обращаются, он будет создавать строку с форматом, описанным кодом геттера.

@ ant2009, Что-нибудь особенное, о чем вы бы хотели поподробнее?

Egor 11.10.2018 00:50

Примеры чего конкретно?

Egor 13.10.2018 15:38

Надеюсь, следующий пример поможет понять лямбда с типом получателя:

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.

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