以下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]
答案 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>
也可以转换为Ordering
(Ordering.comparatorToOrdering
)。
导入Ordering.Implicits._允许您使用x > y
语法,当Ordering[A]
处于隐式作用域时。
答案 1 :(得分:0)
答案“这是否意味着在Scala中Int不可比?”显然是YES,因为如果我用java.lang.Integer替换Int,那么它编译时没有错误。问题是,每次访问ID时我都必须创建一个包装器对象,这种情况经常发生,因此很昂贵。
我想指定ID是Comparable / Ordered,这样我就可以对BaseWithID本身进行排序,并使用可比较的ID在其中明确定义compare方法。
目前,解决方案似乎是没有指定ID是有序的,让具体类实现比较自己,而不是在特征中一次实现它。有人有更好的解决方案吗?