为什么在 Kotlin 中可以像调用普通函数一样调用高阶函数的扩展函数参数?

Why is it possible to call a higher order function's extension function parameter as a normal function in Kotlin?

让我们考虑一下这段代码:

class Receiver

fun higherOrder(extensionBlock: Receiver.() -> Unit) {
    Receiver().extensionBlock() // works
    extensionBlock(Receiver()) // works
}

fun Receiver.extension() = Unit
fun f() {
    Receiver().extension() // works
    extension(Receiver()) // unresolved reference
}

在我看来,扩展的功能签名是 Receiver.() -> Unit,与 extensionBlock 参数相同;即我们可以调用 higherOrder(Receiver::extension) 很好。如果这是真的,我不明白为什么正常的函数调用语法在扩展函数和相同类型的参数之间不一致。我真的很高兴 extension(Receiver()) 是不允许的,所以只有一种方法可以调用扩展函数。所以我想主要问题是 为什么 extensionBlock 有扩展函数签名时我可以做 extensionBlock(Receiver())

这些例子是两个不同的东西:第一个是函数 type with receiver A.() -> B,第二个是扩展函数。

1。接收器功能:

TL;DR: A.() -> B(A) -> B 的不同写法。它不扩展任何内容。

Non-literal values of function types with and without receiver are interchangeable, so that the receiver can stand in for the first parameter, and vice versa. For instance, a value of type (A, B) -> C can be passed or assigned where a A.(B) -> C is expected and the other way around:

val repeatFun: String.(Int) -> String = { times -> this.repeat(times) }
val twoParameters: (String, Int) -> String = repeatFun // OK

Kontlin doc

在您的例子中,应用于解释的代码如下所示:

val typeFunWithReceiver = Receiver.() -> Unit
val typeFunWithParam : (Receiver) -> Unit = typeFunWithReceiver // It does NOT extend Receiver

现在你提到它,我也确实感到困惑。即使在科特林文档中,他们也提到了相似之处:

This behavior is similar to extension functions, which also allow you to access the members of the receiver object inside the body of the function.

Source

2。扩展函数

TL;DR: A.funName() -> B 通过函数 funName() 扩展了 A class。它不是像以前那样的方法类型。

Kotlin provides the ability to extend a class with new functionality without having to inherit from the class or use design patterns such as Decorator.

Source

也许查看字节码有帮助...

extensionBlock : Receiver.() -> Unit 是一个 Function1<Receiver, Unit>。在引擎盖下,这两个调用基本上类似于 extensionBlock.invoke(Receiver())...(您甚至可以在比较中也写下那个...)...所以编译器会发挥两种作用的魔力...为什么它不是也在扩展变体中这样做吗?

扩展函数只是将接收者作为参数的静态函数。现在猜猜为什么它不像高阶函数那样受到支持,尽管从技术上讲这是可能的。 有了下面的东西,那它也应该是一个扩展功能吗?

fun extension(r : Receiver) = Unit // to extend or not to...?

我觉得应该可以,如果你想支持extension(Receiver())扩展函数(从字节码上看没有区别)。现在你不能同时拥有这两个函数,因为你会得到一个平台声明冲突(这基本上说明了为什么 extension(Receiver()) 应该使用扩展函数)。

我想知道如果是这种方式,编译器是否会处理更多或更少的逻辑......老实说,我喜欢高阶函数和扩展函数在这方面的不同......对我来说扩展函数或将某物作为参数的函数是两种不同的东西……如果扩展函数可以两种方式使用,即 extension(Receiver())Receiver().extension(),可能会更加混乱。 . 如果 ~normal 函数也可以作为扩展函数使用,可能会更加混乱...

很遗憾,但也是合乎逻辑的,这在 Java 方面有效:<WrapperClass>.extension(new Receiver())(但我们在那里没有真正的扩展,所以没关系;-))