为通用暂停 Lambda 和常规 Flow Lambda 存在平台冲突的原因是什么?

huangapple go评论47阅读模式
英文:

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 () -&gt; Any) { handler.toString() }
fun test(handler: (Any) -&gt; Flow&lt;Any&gt;) { 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>>

尽管这对解决冲突没有什么用 为通用暂停 Lambda 和常规 Flow Lambda 存在平台冲突的原因是什么? 我建议只是在它们上面加上一些 @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 Function1s, hence the conflict.

In Java, suspend () -&gt; Any would become

Function1&lt;? super Continuation&lt;? super Object&gt;, ? extends Object&gt; 

and (Any) -&gt; Flow&lt;Any&gt; becomes

Function1&lt;? super Object, ? extends Flow&lt;? extends Object&gt;&gt;

Though it's not like that's any useful for solving the conflict 为通用暂停 Lambda 和常规 Flow Lambda 存在平台冲突的原因是什么? I recommend just sticking some @JvmNames 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, &quot;handler&quot;);
    handler.toString();
}

huangapple
  • 本文由 发表于 2023年2月8日 21:12:33
  • 转载请务必保留本文链接:https://go.coder-hub.com/75386317.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定