21

我有一个带有参数化类型的类,我想对其进行比较运算符。我认为我需要使用 Ordered 特征来实现这一点,但编译器不喜欢我使用它。所以说我有以下课程:

class Test[T <: Ordered[T]] {

  def someOp(t: T) if(t < 3) ...
  ...
}

但是,如果我尝试按如下方式使用此类:

val test = new Test[Int]()

编译器抱怨如下:

类型参数 [Test[Int]] 不符合类 Test 的类型参数界限 [T <: Ordered[T]]

有人可以向我解释我在这里做错了什么吗?

4

2 回答 2

24

发生这种情况是因为Int它不是的子类Ordered[Int](请参阅此处为什么)。

但是,有一个隐含的强制Int转换RichInt,它是 的子类Ordered[Int],但不会为下限触发。使用<%(view bounds) 代替它会考虑隐式强制

class Test[T <% Ordered[T]]
于 2013-10-15T15:35:36.880 回答
14

您可以将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],则该元组类型会自动存在一个 Ordering。

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 提供运算符。您只需通过导入 ordering._ 将其置于范围内,如下所示:

def max[T](a:T, b:T)(implicit ordering:Ordering[T]) = { 
  import ordering._; 
  if(a>b) a else b 
}
于 2013-10-15T18:49:18.750 回答