英文:
Why is there a platform clash for generic suspend lambda and regular Flow lambda
问题
- 一个接受不带参数并返回Any类型的挂起函数的重载
- 一个接受一个参数,参数类型为Any,返回类型为Any的常规函数的重载
这是我尝试编写的代码:
import kotlinx.coroutines.flow.Flow
fun test(handler: suspend () -> Any) { handler.toString() }
fun test(handler: (Any) -> Flow<Any>) { handler.toString() }
以下是我得到的错误信息:
平台声明冲突:以下声明具有相同的JVM签名(test(Lkotlin/jvm/functions/Function1;)V):
- fun test(handler: (Any) -> Flow
): Unit defined in se.vermiculus.vericlear.webserver.utility - fun test(handler: suspend () -> Any): Unit defined in se.vermiculus.vericlear.webserver.utility
英文:
I want to create a function with two overloads:
- One that takes a suspend function that takes no arguments and returns Any
- One that takes a regular function that takes one argument: Any and returns Any
This is the code I tried to write:
import kotlinx.coroutines.flow.Flow
fun test(handler: suspend () -> Any) { handler.toString() }
fun test(handler: (Any) -> Flow<Any>) { handler.toString() }
And this is the error i got:
> Platform declaration clash: The following declarations have the same
> JVM signature (test(Lkotlin/jvm/functions/Function1;)V):
> fun test(handler: (Any) -> Flow<Any>): Unit defined in se.vermiculus.vericlear.webserver.utility
> fun test(handler: suspend () -> Any): Unit defined in se.vermiculus.vericlear.webserver.utility
答案1
得分: 1
因为悬挂 Lambda 类型在 JVM 中表示为具有额外的 Continuation
参数。也请参考此处所示的示例,或者尝试从 IntelliJ 中的 Java 文件中调用您的 Kotlin 函数。
在调用悬挂 Lambda 时,底层发生的是,在调用后的所有代码都被包装在一个"continuation"中,并传递给 Lambda。这段代码将在挂起完成后"继续"运行。
由于挂起 Lambda 中有额外的参数,因此在 JVM 表示中,两个函数都有一个参数,因此都表示为 Function1
,从而引发冲突。
在 Java 中,suspend () -> Any
会变成
Function1<? super Continuation<? super Object>, ? extends Object>
而 (Any) -> Flow<Any>
会变成
Function1<? super Object, ? extends Flow<? extends Object>>
尽管这对解决冲突没有什么用 我建议只是在它们上面加上一些 @JvmName
。
英文:
The reason is that suspending lambda types are represented in the JVM as having an extra Continuation
parameter. See also the example presented here, or just try to call your Kotlin function from a Java file in IntelliJ.
What happens under the hood when you call the suspending lambda is, all the code after the call gets wrapped up in a "continuation", and also gets passed to the lambda. That's the code that will "continue" to run after the suspension is done.
Because of the extra parameter in the suspend lambda, both of your functions have 1 parameter in the JVM representation, and hence are both represented as Function1
s, hence the conflict.
In Java, suspend () -> Any
would become
Function1<? super Continuation<? super Object>, ? extends Object>
and (Any) -> Flow<Any>
becomes
Function1<? super Object, ? extends Flow<? extends Object>>
Though it's not like that's any useful for solving the conflict I recommend just sticking some @JvmName
s on it.
答案2
得分: 0
这是因为这两个函数都被翻译成相同的字节码。
类似这样:
import kotlin.jvm.functions.Function1;
import kotlin.jvm.internal.Intrinsics;
import org.jetbrains.annotations.NotNull;
public final void test(@NotNull Function1 handler) {
Intrinsics.checkNotNullParameter(handler, "handler");
handler.toString();
}
英文:
This is because both functions are translated into the same bytecode.
Something like this:
import kotlin.jvm.functions.Function1;
import kotlin.jvm.internal.Intrinsics;
import org.jetbrains.annotations.NotNull;
public final void test(@NotNull Function1 handler) {
Intrinsics.checkNotNullParameter(handler, "handler");
handler.toString();
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论