2011-07-24 25 views
5

以下Scala的聲明是確定:Scala泛型:Int不符合Comparable?

trait Base[B <: Base[B,M,ID], M <: Meta[B,M,ID], ID <: Comparable[ID]] { 
    // ... 
} 

trait Meta[B <: Base[B,M,ID], M <: Meta[B,M,ID], ID <: Comparable[ID]] extends Ordered[Meta[_,_,_]] { 
    // ... 
} 

trait BaseWithID[B <: BaseWithID[B,M,ID], M <: Meta[B,M,ID], ID <: Comparable[ID]] extends Base[B,M,ID] with Ordered[B] { 
    // ... 
} 


trait BaseWithIntID[B <: BaseWithIntID[B,M,ID], M <: MetaWithIntID[B,M,ID], ID <: Comparable[ID]] extends BaseWithID[B,M,ID] { 
    // ... 
} 

trait MetaWithIntID[B <: BaseWithIntID[B,M,ID], M <: MetaWithIntID[B,M,ID], ID <: Comparable[ID]] extends Meta[B,M,ID] { 
    // ... 
} 

但以下兩個都不是:

trait BaseWithIntID[B <: BaseWithIntID[B,M], M <: MetaWithIntID[B,M]] extends BaseWithID[B,M,Int] { 
    // ... 
} 

trait MetaWithIntID[B <: BaseWithIntID[B,M], M <: MetaWithIntID[B,M]] extends Meta[B,M,Int] { 
    // ... 
} 

不同的是,我刪除了BaseWithIntID和MetaWithIntID ID類型參數,並指定int明確他們各自的基本特徵。但是這不能編譯,那麼這是否意味着在Scala中Int不是Comparable?如果是這樣,我做錯了什麼?我嘗試了Ordered而不是Comparable,並沒有什麼不同。

我使用Eclipse,和往常一樣,該錯誤信息是無用的:

type arguments [B,M,Int] do not conform to trait BaseWithID's type parameter bounds [B <: BaseWithID[B,M,ID],M <: Meta[B,M,ID],ID <: java.lang.Comparable[ID]] 

它只是說,什麼是錯的,但不是這類型參數是錯誤的,以及爲什麼。看看this question,我想我可以試試「ID <%Comparable [ID]」,但這在特質聲明中不合法。

其實,這並不工作,要麼(與相同的錯誤消息):

trait TestBase extends BaseWithID[TestBase,TestMeta,Int] 

trait TestMeta extends Meta[TestBase,TestMeta,Int] 
+0

ID <%Comparable [ID]'的問題是它會自動定義一個隱式參數。由於特徵不允許有參數,它不會工作。然而,作爲一個班級,你可以做到。 –

回答

8

int在scala中確實沒有可比性,當然是因爲它實際上實現爲java int而不是java.lang.Integer。我不確定這是不可能的,C#struct(值類型)可能會實現接口,但這不是在這裏完成的。

你通常會做的是說有一個Ordering可用於你的ID類型的隱式範圍,ID : Ordering

在一個簡單的例子:

import Ordering.Implicits._ 
def max[A : Ordering](x: A, y: A) : A = if (x > y) then x else y 

這相當於傳遞一個訂購(這是同樣的事情作爲java.util.Comparator)給該函數。事實上,聲明

def max[A : Ordering](x: A, y: A) 

轉化爲

def max[A](x: A, y: A)(implicit ev: Ordering[A]) 

其中ev是一個新鮮的名字。如果A:Ordering出現在類而不是方法定義上,如代碼中那樣,它將轉換爲構造函數的隱式參數,如果需要,它將保留在字段中,並且可以在類中的隱式範圍中使用。這比將A強制爲Comparable(scala中的Ordered)更靈活,因爲它可能用於不屬於您的類並且尚未實現Comparable的類。你也可以在同一個類別之間選擇不同的Odering,如果只是顛倒默認的那個:在Ordering上有一個def reverse : Ordering方法就是這樣。

不好的一面是,虛擬機不可能內聯調用比較方法,但它不可能用通用接口方法。

在java中實現Comparable<T>的類型通過對象Ordering中的隱式方法(ordered)自動在隱式範圍內獲得Ordering。 java Comparator<T>也可以轉換爲OrderingOrdering.comparatorToOrdering)。

導入當Ordering[A]處於隱式範圍時,Ordering.Implicits._允許您使用漂亮的x > y語法。

0

答案「難道說,誠信是不是在斯卡拉可比性?」顯然是YES,因爲如果我用java.lang.Integer替換Int,那麼它編譯時沒有錯誤。問題是,我每次訪問ID時都必須創建一個包裝器對象,這會經常發生,因此很昂貴。

我想指定ID是Comparable/Ordered,這樣我可以使BaseWithID本身有序,並通過使用可比ID來明確地定義比較方法。

目前的解決方案似乎是不指定ID是有序的,讓具體類實現自身比較,而不是在特徵中實現一次。有沒有人有更好的解決方案?

+0

要添加到我的答案,在「昂貴」的方面,對比較方法 - Ordering.comare(x,y)的調用可能不會被內聯,並且您也可能支付拳擊費用。那麼它會在Comparable中使用java。另一方面,可以調用x> y的包裝意味着新的ord.Ops(x)。>(y),它從實現的角度來看new new Ordering.Ops(ord,x),其中ord是訂購。很可能避免創建這個對象。如果需要(基準測試),你可以直接調用orders.compare,這比在java中調用compare差不了多少。 –

+0

P.S. 「可能避免創建此對象」意味着「VM可能實際上不會創建對象」。這不僅僅是可能的,但確定的是,你可以通過不使用x> y語法來避免創建對象。 –