Scala泛型:Int不符合Comparable?

时间:2011-07-24 09:33:44

标签: generics scala int comparable

以下Scala声明没问题:

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。但是这不会编译,那么这是否意味着Int在Scala中不可比较?如果是的话,我做错了什么?我尝试了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&lt;%Comparable [ID]”,但这在特质声明中是不合法的。

实际上,这也不起作用(使用相同的错误消息):

trait TestBase extends BaseWithID[TestBase,TestMeta,Int]

trait TestMeta extends Meta[TestBase,TestMeta,Int]

2 个答案:

答案 0 :(得分:9)

Int在scala中确实不具有可比性,当然因为它实际上是以java int实现的,而不是java.lang.Integer。我不确定那是不可能的,C#struct(值类型)可以实现接口,但这不是在这里完成的。

您通常会说,您的ID类型的隐式范围中有Ordering可用ID : Ordering

举一个简单的例子:

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

这等于将Ordering(与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,如果只是颠倒默认的那个:def reverse : Ordering上有一个Ordering方法可以做到这一点。

不好的一面是,VM不太可能内联对比较方法的调用,但它不太可能是泛型中的接口方法。

在java中实现Comparable<T>的类型通过对象Ordering中的隐式方法(ordered)自动在隐式范围内获得Ordering。 java Comparator<T>也可以转换为OrderingOrdering.comparatorToOrdering)。

导入Ordering.Implicits._允许您使用x > y语法,当Ordering[A]处于隐式作用域时。

答案 1 :(得分:0)

答案“这是否意味着在Scala中Int不可比?”显然是YES,因为如果我用java.lang.Integer替换Int,那么它编译时没有错误。问题是,每次访问ID时我都必须创建一个包装器对象,这种情况经常发生,因此很昂贵。

我想指定ID是Comparable / Ordered,这样我就可以对BaseWithID本身进行排序,并使用可比较的ID在其中明确定义compare方法。

目前,解决方案似乎是没有指定ID是有序的,让具体类实现比较自己,而不是在特征中一次实现它。有人有更好的解决方案吗?