我有一个参数化类型的类,我想做比较运算符。我认为我需要使用Ordered trait来实现这一点,但编译器不喜欢我使用它。所以说我有以下课程:
class Test[T <: Ordered[T]] {
def someOp(t: T) if(t < 3) ...
...
}
但是,如果我尝试按如下方式使用此类:
val test = new Test[Int]()
编译器抱怨如下:
类型参数[Test [Int]]不符合类Test的类型 参数边界[T&lt ;:Ordered [T]]
有人可以向我解释我在这里做错了吗?
答案 0 :(得分:20)
这是因为Int
不是Ordered[Int]
的子类(请参阅here为什么)。
但是,从Int
到RichInt
的隐式强制是Ordered[Int]
的子类,但它不会触发下限。使用<%
(查看边界)代替which will consider implicit coercions:
class Test[T <% Ordered[T]]
答案 1 :(得分:10)
您可以使用Ordering[T]类型类作为隐式参数。如果你想编写一个通用的max函数,它将如下所示:
def max[T](a:T, b:T)(implicit ordering:Ordering[T]) = {
if(ordering.gt(a,b)) a else b
}
对于原始数据类型,如Int,Float,...,范围内有一个隐式的Ordering [T],以便您可以按预期使用它。
max(1,2) // gives 2
对于实现Ordered [T]的所有类型,还有一个隐式提供Ordering [T]。
范围内还有各种方法可以组合排序。例如,如果你有一个N元组,其中每个元素都有一个Ordering [T],那么自动存在一个元组类型的排序。
max((1,2), (3,4)) // gives (3,4) because 3 is larger than 1
但如果您对任何隐式提供的排序不满意,您可以自己编写并明确传递它,或者甚至将其作为隐式val 在范围内获取。像这样:
val negativeIntOrdering = new Ordering[Int] {
def compare(a:Int,b:Int) = b - a
}
max(1,2)(negativeIntOrdering) // gives 1
因此,基于类型的方法比基于继承的方法更灵活。这就是像spire这样的数学库广泛使用它的原因。
上面代码不太好的一件事是你必须使用lt方法而不是运算符。但也有一个解决方案。 Ordering有一个名为mkOrderingOps的隐式方法,为T提供运算符。你只需要通过导入orders._来获取它,如下所示:
def max[T](a:T, b:T)(implicit ordering:Ordering[T]) = {
import ordering._;
if(a>b) a else b
}