正确理解 T.() lambda

Correct understanding of T.() lambda

我无法理解 lambda

特别是 run() 中的 T.() -> R 更令人困惑。

public inline fun <T, R> T.run(block: T.() -> R): R = return block()

问题

fun main() {
    test {
        this.replace("3","B")
    }
}

fun test(block: String.(Int) -> Unit) {
    "TEST".block(7)
}

在这段代码中,在block parameter中,String.()表示将block定义为一个extension function of the String class?所以block在调用的时候需要String value?

并且,

fun main() {
    "A".test {
        this.replace("3","B")
    }
}


fun String.test(block: String.(Int) -> Unit) {
    block(7)
}

在这段代码中调用block时,为什么不需要receiver type

in the block parameter, String.() means to define block as an extension function of the String class? So block requires String value when calling?

是的。该块实际上是 String class 上的扩展函数:在块内,this 是相关的 String 实例。

When calling the block in this code, why don't we need the receiver type?

因为已经有一个隐式接收器。 test() 本身是 String 上的扩展函数,因此在 test() 的主体内, this 是一个字符串。因此,您可以调用 String 的任何方法,而无需使用 this. 限定它们——包括扩展方法,例如 block.


考虑使用“真实”方法而不是扩展方法的更简单的情况:

class C {
    fun a() {
        // …
    }

    fun b() {
        a() // Implicit receiver
    }
}

a()是classC的一个方法,所以它需要C的一个实例。但是b()在调用a()时不需要指定C的实例,因为它已经有自己的接收者了。

可以写成this.a(),但没必要,因为this总是隐含的接收者,当你不要指定一个。 (有些人似乎喜欢明确的 this.,但对我来说这只是毫无意义的视觉噪音……)

虽然扩展方法在“幕后”的实现方式略有不同,但语法的工作方式完全相同。所以在你的第二个例子中对 block() 的调用有一个隐含的 this..

In particular, things like T.() -> R in the run() is more confusing.

public inline fun <T, R> T.run(block: T.() -> R): R = block()

这里的TR是泛型,可以是任何数据类型IntStringClass等。你明白了。

block: T.() -> R,意思是 block 必须是类型 Textension 函数,可以 return 任何类型 R 而这个 R 可以是任何东西,UnitStringClass

A lambda returns 其最后一个表达式的值,因此无论表达式在 lambda 的最后一行,它都会 return 它,即类型 R.

现在,当我们在任何对象上使用 run 方法时,它会为我们提供与 lambda 中的 lambda 接收器 (this) 相同的对象,因为我们的 lambda 是我们调用它的同一类型的扩展函数。

var a = 1
val b = a.run {
        this + 6
        "incremented"
    }

a 上使用 run 方法后,我们的通用 T 类型变为 Int 并且我们的对象 a 在 [=28] 中可用=] 为 this,因为,现在它是 Int.

的扩展函数

lambda中,我们的最后一个表达式是"incremented",它是一个String,所以这里我们的R变成了String的一种类型。由于 run 方法正在 returning 这个 R,变量 b 的值变为 incremented.


In this code, in the block parameter, String.() means to define block as an extension function of the String class? So block requires String value when calling?

如果 block 是一个 extension 函数,那么您不需要传递 String。当您在任何 String 上调用它时,它会使用它。但是,如果 block 不是 extension 函数,那么您将不得不传递它。


fun test(block: String.(Int) -> Unit) {
    "TEST".block(7)
}

.

fun String.test(block: String.(Int) -> Unit) {
    block(7)
}

When calling the block in this code, why don't we need the receiver type?

在后者中,test方法是Stringextension函数,在方法体中作为this可用,所有的函数String 也可用,您可以在接收者对象上使用或不使用 thisblock也是String的扩展函数,可以直接访问

同时,在前者中,方法主体中没有可用的 String 类型的接收者对象,这就是为什么您必须在 String 上显式调用它的原因。