【问题标题】:Confusion with understanding lambda and receivers对理解 lambda 和接收器感到困惑
【发布时间】:2018-10-07 12:31:46
【问题描述】:

Kotlin 版本 1.2.50

我一直在 youtube https://www.youtube.com/watch?v=gPH9XnvpoXE 上关注本教程的一些示例。还有一些事情我已经理解了,但仍然有些混乱。我将 cmets 留在了下面的代码中,我不确定发生了什么。

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

【问题讨论】:

    标签: lambda kotlin extension-function


    【解决方案1】:

    /* 我们是否传入了 lambda 和接收器。接收者是什么*/

    私人乐趣 JavaClientBuilder.twitter(suppler: JavaTwitterBuilder.() -> Unit)

    我们确实在这个函数中有一个接收器,它是JavaClientBuilder 的实例,这个函数将被调用。

    /* 我们调用 JavaTwitterBuilder().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 中的逻辑来初始化该实例。

    /* 我们是否传入了一个什么都不返回的 lambda 和接收器 */

    private fun createClient(suppler: JavaClientBuilder.() -> Unit): JavaClient

    在这种情况下,createClient() 没有接收器,它是一个顶级函数。

    /* 困惑:不确定这一点,因为我们称其为 suppler。只是想知道上面 javaClient {} lambda */

    中调用的 JavaClientBuilder 的补充

    javaClientBuilder.suppler()

    suppler 是一个 lambda,JavaClientBuilder 是接收器类型,这允许我们在新创建的 JavaClientBuilder 实例上调用它。

    /* 我明白了,这是一个扩展函数,它格式化并从调用它的 JavaClient 对象返回字符串 */

    私有 val JavaClient.toConsole: 字符串 得到()= "创建的客户是:${twitter.handle} ${company.name}"

    对!只是一个小的修正,它是一个扩展属性。属性可以有自定义的 getter 和 setter。这个属性定义了一个自定义的 getter,所以实际上每当访问这个属性时,它都会产生一个字符串,其格式由 getter 代码描述。

    【讨论】:

    • @ant2009,有什么特别想了解的细节吗?
    • 具体是什么例子?
    【解决方案2】:

    希望以下示例有助于理解具有接收器类型的 lambda:

    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。

    【讨论】:

      猜你喜欢
      • 2012-03-01
      • 2013-05-15
      • 2012-03-22
      • 1970-01-01
      • 2018-08-30
      • 2018-11-13
      • 2021-10-22
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多