Kotlin:两个具有不同类型函数输入的同名函数

Kotlin: Two Functions Of Same Name With Different Type Function Inputs

看看下面的代码。

fun stuff(func: () -> Int) {
    println(func().toString())
}

fun stuff(func: () -> String) {
    println(func())
}

fun main() {
    stuff { 1 }
}

这给了我一个奇怪的错误。

Overload resolution ambiguity: public fun stuff(func: () -> Int): Unit defined in root package in file File.kt public fun stuff(func: () -> String): Unit defined in root package in file File.kt
'return' is not allowed here
The integer literal does not conform to the expected type Unit

我不确定为什么并试图解决这个问题。我可以使用 Java 泛型,但我希望在纯 kotlin 中工作。也可以用参数化类型做一些事情,比如

fun <T>stuff(func: () -> T)

但是如果东西的调用者不知道它传入的是什么,这就不那么优雅了。

我也看到了这个回答:

由于以下错误,这不起作用:

Duplicate method name "stuff" with signature "(Lkotlin.jvm.functions.Function0;)V"

因此,基于这个错误,我猜我想这样做是不可能的……但我充满希望!

会喜欢这里的一些想法。

这是一个奇怪的错误……当我自己在 IntelliJ 中尝试时,我在两个函数声明中都收到以下错误:

Platform declaration clash: The following declarations have the same JVM signature (stuff(Lkotlin/jvm/functions/Function0;)V)

…后跟两个函数签名。并且 then 在最后的通话中:

Overload resolution ambiguity. All these functions match.

…后面还有两个函数签名。

(我完全没有得到你的最后两个错误。这些错误可能来自你的代码的不同版本吗?)

第一个告诉你这里真正的问题是什么:虽然 () -> Int() -> String 在 Kotlin 中是不同的类型,但它们在 Java 字节码中编译为相同的类型. (原始签名是 Lkotlin/jvm/functions/Function0;,对 kotlin.jvm.functions.Function0 实例的引用,它是 Kotlin 运行时用来实现函数引用的接口。问题在于它是通用的:return类型由类型参数指示。)因此,两个 Kotlin 函数都编译为 相同的 函数类型,因此 stuff 的两个版本都具有相同的 JVM 签名。这当然是不允许的。

恐怕这也意味着您自己使用泛型来解决它的建议也行不通,原因完全相同……

在这种特殊情况下,您可以为 Any 参数编写一个方法,因为您可以对任何对象调用 toString()!但当然这不会更普遍。

(这是 JVM 上的普遍烦恼,是选择 type erasure to implement generics.  You see it in all sorts of cases 的不幸结果……)

return 类型永远不会构成 method/function 签名。

两个 methods/functions 具有相同的签名,如果它们具有相同的名称和相同的参数,无论 return 类型如何。

这适用于任何允许重载的语言,否则在像 stuff(stuff(...)) 这样的结构中会存在隐含的歧义,无法决定调用哪个外部 stuff()