Kotlin编译器的类型推断无法选择调用哪种方法(泛型类型的歧义)

时间:2017-01-05 19:35:48

标签: generics kotlin overloading kotlin-interop

所以,我有一些带有这些签名的Java方法(为简单起见,删除了注释和代码体):

public class JavaClass {
  public static <E extends CharSequence> E join(E... array) { ... }
  public static <E extends CharSequence> E join(CharSequence separator, E... array) { ... }
}

我在Kotlin中有一些代码,它们调用'join'方法:

class KtClass {
    fun test(vararg array: String) {
        JavaClass.join(*array)
    }
}

到目前为止一切顺利;它将传播varargs并调用前方法签名。 Okie dokie!

例如,如果我想使用'separator'参数调用后一种方法签名,则会出现问题:

class KtClass {
    fun test(vararg array: String) {
        JavaClass.join("<br>", *array)
    }
}

此代码无法编译。编译器无法决定调用哪个方法。错误:

  

错误:(5,13)Kotlin:未完成类型推断,不能在以下候选人中进行选择:   public open fun join(vararg array:String!):String!在JavaClass中定义   public open fun join(separator:CharSequence!,vararg array:String!):String!在JavaClass中定义

我甚至无法命名参数,因为Kotlin不会让非Kotlin函数的参数命名。

编辑:用Java方法标题中的普通 String 引用替换了 E 泛型类型参数,它运行正常!所以我猜这是类型推断与泛型类型或类似东西的不兼容性?

我很确定这必须是传播运算符(*)。但是如果我不使用它,我就无法将varargs参数array传递给join函数。

如何在不触及Java代码的情况下解决这个问题?

是的,我知道有Array.joinToString扩展函数,但这只能解决这种特殊情况。我需要知道一个通​​用的解决方案。

3 个答案:

答案 0 :(得分:2)

我认为这不是特定的Kotlin。问题是泛型参数E的类型为CharSequence,因此您的调用变为类似join("separator", "word1", "word2")的调用,实际上,自第一个参数以来,类型为E == CharSequence的模糊不清与其他args的类型相同。

答案 1 :(得分:1)

看起来您需要在Java中创建一个辅助类来桥接互操作问题。 e.g:

public class JavaClassInterop {
    public static <E extends CharSequence> E joinSeparatedBy(CharSequence separator,
                                                             E... array) {
        return JavaClass.join(separator, array);
    }
}

然后你可以同时打电话:

import JavaClass.join
import JavaClassInterop.joinSeparatedBy

fun main(args: Array<String>) {
    join(*args)
    joinSeparatedBy("<br>", *args)
}

答案 2 :(得分:1)

tldr

可能您使用可空类型

工作不正常

我一直在努力解决这个错误,但终于想出了一个解决方案。我一开始就有这个

user.items.apply {
        removeAll(otherItems)
        removeAll(otherItems2)
    }

items集合是MutableSet吗?所以它可以为空,而其他Items集合也可以为空。 添加后呢?在apply之前,将非可空集合传递给removeAll函数,错误消失了。

user.items?.apply {
        removeAll(otherItems.orEmpty())
        removeAll(otherItems2.orEmpty())
    }