6

java.util.Collections该类中,我们有两种sort方法的变体,一种采用带有对应的任意对象列表Comparator

public static <T> void sort(List<T> list, Comparator<? super T> comparator)

还有一个需要Comparable对象列表的:

public static <T extends Comparable<? super T>> void sort(List<T> list)

我在想如何将这种带有有界通配符的方法签名转换为 Scala。对于第一个版本,我按照字面意思翻译了签名,乍一看没有编译问题:

def sort[T](list: List[T], comparator: Comparator[_ >: T]) { ??? }

但后来我发现我无法使用以下参数调用此方法:

val comparator = new Comparator[Object] {
    def compare(o1: Object, o2: Object) = ???
}
val list = new ArrayList[Number]
sort[Object](list, comparator)

最后一行给出了这个编译错误,即使我明确地将类型指定TObject.

类型不匹配; 找到:java.util.ArrayList[Number] 必需:java.util.List[Object] 注意:Number <: Object,但 Java 定义的特征 List 在类型 E 中是不变的。您可能希望研究通配符类型,例如_ <: Object. (SLS 3.2.10)

实际上,我发现直接调用唯一的 Java 方法甚至是不可能的,因为它会因相同类型的错误而失败。

Collections.sort[Object](list, comparator)

至于具有可比列表的版本,我提出了以下声明:

def sort[T <: Comparable[_ >: T]](list: List[T]) { ??? }

但这根本不起作用:

涉及类型 T 的非法循环引用


我究竟做错了什么?Scala 变体泛型是否遵循与 Java 不同的规则?Collections.sort如何在没有实际出现编译错误的情况下调用该方法?

边注:

不,我并不是真的在问如何在 Scala 中对列表进行排序。我知道 Scala 有自己的集合、排序函数和比较对象(例如OrderedOrdering特征)的不同方法。我的问题涉及泛型方法的一般问题以及泛型从 Java 到 Scala 的翻译。

4

2 回答 2

4

您给出了错误的类型参数T:您对 a 进行排序List[Number],而不是 a List[Object]

sort[Number](list, comparator)

将工作。

如果你想在没有类型参数的情况下调用 sort,你需要定义两个参数列表(因为类型推断在 Scala 中是如何工作的):

def sort[T](list: List[T])(comparator: Comparator[_ >: T]) { ??? }

// Then
sort(list)(comparator)

您可能要考虑使用对协方差有适当支持的 Scala 类型(即在 Scala 中 aList[Number]是 a List[Object])。

关于具有可比性的版本,您必须明确编写通配符:

def sort[T <: Comparable[T], U <: T](list: List[U]) { ??? }
于 2013-05-07T23:50:07.520 回答
3

您可以使用以下命令调用 Java 变体(或您的变体):

Collections.sort[Number](list, comparator)

这里的问题是因为 Java 泛型类型是不变的。换句话说,这在 Java 中失败了:

List<Number> l1;
List<Integer> l2 = l1; //contravariance fails
List<Object> l3 = l1; //covariance fails

在 Scala 中,泛型类型参数可以在其声明中声明为协变或逆变。Scala 的 List 类型参数被声明为协变的(之所以有效,是因为它是不可变的)。换句话说,这是有效的:

val l1: List[Number] = ???
val l2: List[Object] = l1 //valid

但是由于您使用的是 Java java.util.List,所以这不是一个选择。

于 2013-05-07T23:50:26.373 回答