2013-05-07 68 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