简体   繁体   English

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

[英]Kotlin compiler's type inference can't choose which method to call (ambiguity with generic types)

So, I have some Java methods with these signatures (removed annotations and code body for the sake of simplicity): 所以,我有一些带有这些签名的Java方法(为简单起见,删除了注释和代码体):

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

And I have some code in Kotlin, which calls the 'join' method: 我在Kotlin中有一些代码,它们调用'join'方法:

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

So far so good; 到现在为止还挺好; it will spread the varargs and call the former method signature. 它将传播varargs并调用前方法签名。 Okie dokie! 好的!

The problem comes if, for example, I want to call the latter method signature, with a 'separator' argument: 例如,如果我想使用'separator'参数调用后一种方法签名,则会出现问题:

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

This code won't compile. 此代码将无法编译。 The compiler can't get to decide which method to call. 编译器无法决定调用哪个方法。 The error: 错误:

Error:(5, 13) Kotlin: Cannot choose among the following candidates without completing type inference: public open fun join(vararg array: String!): String! 错误:(5,13)Kotlin:如果没有完成类型推断,不能在以下候选者中进行选择:public open fun join(vararg array:String!):String! defined in JavaClass public open fun join(separator: CharSequence!, vararg array: String!): String! 在JavaClass public open fun join中定义(separator:CharSequence!,vararg array:String!):String! defined in JavaClass 在JavaClass中定义

I can't even name the arguments because Kotlin doesn't let argument naming for non-Kotlin functions. 我甚至无法命名参数,因为Kotlin不让非Kotlin函数的参数命名。

EDIT: Replaced the E generic type parameter with plain String references in the Java method headers, and it worked! 编辑:用Java方法头中的普通字符串引用替换了E泛型类型参数,它工作正常! So I guess this to be an incompatibility of type inference with generic types or something like that? 所以我猜这是类型推断与泛型类型或类似东西的不兼容性?



I'm pretty sure this has to be something with the spread operator (*). 我很确定这必须是扩展运算符 (*)。 But I can't pass the varargs parameter array to the join function if I don't use it. 但是如果我不使用它,我无法将varargs参数array传递给join函数。

How can I solve this without touching the Java code? 如何在不触及Java代码的情况下解决这个问题?

YES, I KNOW that there is Array.joinToString extension function, but this would solve only this particular case. 是的,我知道有Array.joinToString扩展函数,但这只能解决这个特殊情况。 I need to know a generic solution. 我需要知道一个通​​用的解决方案。

I don't think that's Kotlin specific. 我不认为这是特定的Kotlin。 The problem is that the generic argument, E is of type CharSequence so your call becomes something like join("separator", "word1", "word2") which is, indeed, ambiguous since the first argument, of type E == CharSequence is the same as the type of the other args. 问题是泛型参数E的类型是CharSequence所以你的调用变成了join("separator", "word1", "word2") ,它实际上是第一个参数的模糊,类型为E == CharSequence与其他args的类型相同。

It looks like you will need to create a helper class in Java to bridge the interop issue. 看起来您需要在Java中创建一个帮助程序类来桥接互操作问题。 eg: 例如:

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

Then you can call both: 然后你可以同时打电话:

import JavaClass.join
import JavaClassInterop.joinSeparatedBy

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

tldr tldr

Probably you work incorrectly with nullable types 可能你错误​​地使用可空类型

I was struggling with this error for a while, but finally came up with a solution. 我在这个错误中挣扎了一段时间,但终于想出了一个解决方案。 I had this at first 我起初有这个

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

The items collection is a MutableSet? 物品集合是一个MutableSet? so it is nullable, and otherItems collections are nullable too. 所以它可以为空,而其他Items集合也可以为空。 So after adding ? 添加后呢? before the apply, and passing non nullable collection to the removeAll function, the errors disappeared. 在apply之前,将非可空集合传递给removeAll函数,错误消失了。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM