正确理解 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()
这里的T
和R
是泛型,可以是任何数据类型Int
、String
或Class
等。你明白了。
block: T.() -> R
,意思是 block
必须是类型 T
的 extension
函数,可以 return 任何类型 R
而这个 R
可以是任何东西,Unit
、String
、Class
等
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
方法是String
的extension
函数,在方法体中作为this
可用,所有的函数String
也可用,您可以在接收者对象上使用或不使用 this
。 block
也是String
的扩展函数,可以直接访问
同时,在前者中,方法主体中没有可用的 String
类型的接收者对象,这就是为什么您必须在 String
上显式调用它的原因。
我无法理解 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 defineblock
as an extension function of theString
class? Soblock
requiresString
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()
这里的T
和R
是泛型,可以是任何数据类型Int
、String
或Class
等。你明白了。
block: T.() -> R
,意思是 block
必须是类型 T
的 extension
函数,可以 return 任何类型 R
而这个 R
可以是任何东西,Unit
、String
、Class
等
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 requiresString
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
方法是String
的extension
函数,在方法体中作为this
可用,所有的函数String
也可用,您可以在接收者对象上使用或不使用 this
。 block
也是String
的扩展函数,可以直接访问
同时,在前者中,方法主体中没有可用的 String
类型的接收者对象,这就是为什么您必须在 String
上显式调用它的原因。