它与扩展功能有什么关系?为什么 with
a function 不是关键字?
该主题似乎没有明确的文档,只有引用 extensions 的知识假设。
最佳答案
确实,关于接收器概念的现有文档似乎很少(只有 small side note related to extension functions ),这令人惊讶:
with
,如果不知道接收者,它可能看起来像一个关键字; { toLong() }
没有多大意义,对吧?事实上,将它分配给 (Int) -> Long
的 function type - 其中 Int
是(唯一的)参数,并且返回类型是 Long
- 将正确地导致编译错误。您可以通过简单地使用隐式单个参数 it
限定函数调用来解决此问题。但是,对于 DSL 构建,这会导致一系列问题:html { it.body { // how to access extensions of html here? } ... }
这可能不会导致 HTML DSL 出现问题,但可能会导致其他用例出现问题。 it
调用乱扔代码,特别是对于大量使用其参数(即将成为接收器)的 lambda。 Int
作为 接收器 (不是作为参数!)的函数类型,代码突然编译:val intToLong: Int.() -> Long = { toLong() }
这里发生了什么?Int.() -> Long // taking an integer as receiver producing a long
String.(Long) -> String // taking a string as receiver and long as parameter producing a string
GUI.() -> Unit // taking an GUI and producing nothing
此类函数类型的参数列表以接收器类型为前缀。val intToLong: Int.() -> Long = { toLong() }
,它有效地导致代码块在不同的上下文中进行评估,就好像它被放置在 Int
中的函数中一样。这是一个使用手工制作类型的不同示例,可以更好地展示这一点:class Bar
class Foo {
fun transformToBar(): Bar = TODO()
}
val myBlockOfCodeWithReceiverFoo: (Foo).() -> Bar = { transformToBar() }
有效地变成(在头脑中,不是代码明智的 - 你实际上不能在 JVM 上扩展类):class Bar
class Foo {
fun transformToBar(): Bar = TODO()
fun myBlockOfCode(): Bar { return transformToBar() }
}
val myBlockOfCodeWithReceiverFoo: (Foo) -> Bar = { it.myBlockOfCode() }
请注意在类内部,我们不需要使用 this
来访问 transformToBar
- 同样的事情发生在具有接收器的块中。class Foo
class Bar
fun Foo.functionInFoo(): Unit = TODO()
fun Bar.functionInBar(): Unit = TODO()
inline fun higherOrderFunctionTakingFoo(body: (Foo).() -> Unit) = body(Foo())
inline fun higherOrderFunctionTakingBar(body: (Bar).() -> Unit) = body(Bar())
fun example() {
higherOrderFunctionTakingFoo {
higherOrderFunctionTakingBar {
functionInFoo()
functionInBar()
}
}
}
请注意,如果 Kotlin 语言的此功能似乎不适合您的 DSL,那么 @DslMarker 就是您的 friend !toLong()
,而不必以某种方式引用该数字。 Maybe your extension function shouldn't be an extension? with
,一个标准库 函数 而不是关键字,存在 - 修改代码块的范围以节省冗余类型的行为如此普遍,语言设计者把它放在标准库中。 关于kotlin - Kotlin 中的 "receiver"是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45875491/