Scala在Comparator.thenComparing中解析为错误覆盖

zal*_*ale 6 generics scala scala-java-interop

我正在尝试翻译以下Java代码:

import java.util.Comparator;

public class ComparatorTestJava {
    public static void test() {
        Comparator<String> cmp = (s1, s2) -> 0;
        cmp = cmp.thenComparing(s -> s);
    }
}
Run Code Online (Sandbox Code Playgroud)

进入斯卡拉.我认为这应该有效:

import java.util.{Comparator, function}

object ComparatorTest {
  var comparator: Comparator[String] = (t1, t2) ? 0
  comparator = comparator.thenComparing(new function.Function[String, String] {
    override def apply(t: String): String = t
  })
}
Run Code Online (Sandbox Code Playgroud)

但它失败并出现以下错误:

Error:(7, 41) type mismatch;
 found   : java.util.function.Function[String,String]
 required: java.util.Comparator[? >: String]
  comparator = comparator.thenComparing(new function.Function[String, String] {
Run Code Online (Sandbox Code Playgroud)

看起来Scala编译器确信我正在尝试使用thenComparing(Comparator)而不是thenComparing(Function).有什么方法可以告诉它它是什么?或者这实际上不是问题?

(我意识到还有其他的,也许更惯用的方法在Scala中构建比较器,但我很想知道为什么会失败.)

And*_*kin 5

鉴于定义

val comparator: Comparator[String] = (t1, t2) => 0
val f: function.Function[String, String] = s => s
Run Code Online (Sandbox Code Playgroud)

以下错误与您的问题中的错误相同:

comparator.thenComparing(f)
Run Code Online (Sandbox Code Playgroud)

但这成功编译:

comparator.thenComparing[String](f)
Run Code Online (Sandbox Code Playgroud)

每当尝试使用Scala的通用Java接口时,这是一种非常常见的错误类型.原因是Java的使用站点差异与Scala的声明站点方差不相符,因此Java会Comparator<? super T>转换为通配符类型Comparator[_ >: T],并且它会以某种方式混淆类型推断算法(特别是如果将它与重载方法和SAM结合使用).但是,一旦识别出来,通过明确指定类型参数就可以很容易地解决问题,在这种情况下,添加显式[String]就足够了.