2013-05-07 266 views
6

java.util.Collections类,我们有sort方法的两个变种,即需要任意对象的列表,并附有相应的Comparator翻译从Java泛型通配符斯卡拉

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) 

我在想一个woulds如何转化与博这样的方法签名没有通配符的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] required:java.util.List [Object]注意:数字<:对象,但Java定义的特征列表在E中不变。您可能希望研究通配符类型,例如_ <: Object 。 (SLS 3.2.10)

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

Collections.sort[Object](list, comparator) 

至于相媲美列表框中的版本,我想出了这个声明:

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

但是,这并不在所有的工作:

非法循环引用涉及类型T


我在做什么错?斯卡拉变种泛型遵循不同规则的Java?如何在不实际发生编译错误的情况下调用一个调用Collections.sort方法?

旁注:

不,我真的不问我怎么能进行排序Scala中的一个列表。我知道Scala拥有自己的一套集合,排序函数和用于比较对象的不同方法(如OrderedOrdering特征)。我的问题涉及泛型方法的一般问题以及从Java到Scala的泛型翻译。

回答

4

你给了错误的类型参数T:您排序List[Number],而不是一个List[Object]

sort[Number](list, comparator) 

会工作。

如果要排序调用无类型参数,你需要定义两个参数列表(因为类型推断Scala中是如何工作的):

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

// Then 
sort(list)(comparator) 

你可能要考虑使用Scala的类型,对协方差有适当的支持(即在斯卡拉List[Number]List[Object])。

关于相媲美的版本,你必须明确地写通配符:

def sort[T <: Comparable[T], U <: T](list: List[U]) { ??? } 
+0

对啊,我现在看到了错误!即使在Java中,客户端代码也需要是“集合”。 sort(list,comparator)',而不是'Collections。 sort(list,comparator)'。 – Natix 2013-05-08 00:10:51

+0

另外,关于分割参数列表的好消息,我并不知道!你还可以详细说明“Comparable”列表的版本吗? – Natix 2013-05-08 00:13:15

+0

@Natix查看更新的答案。 – gzm0 2013-05-08 01:20:25

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这是不是一种选择。

+0

对啊,我现在看到了错误!即使在Java中,客户端代码也需要是“集合”。 sort(list,comparator)',而不是'Collections。 sort(list,comparator)'。 – Natix 2013-05-08 00:11:19

+0

你能否详细说一下“Comparable”列表的版本?顺便说一下,我认为Scala的列表类型参数实际上是_covariant_('List [+ A]')。 – Natix 2013-05-08 00:16:37

+0

@Natix:我希望我能回答你关于可比案件的问题。我最近刚刚从Java介绍给Scala,你所拥有的直接等价于我在Java中所做的事情(实际上这也是真正的实现)。这似乎是完全矫枉过正要求第二个类型参数。 – 2013-05-08 03:26:15