如何比较Scala特征中的Ordered抽象类型?

时间:2012-02-13 00:11:28

标签: scala abstract-type

鉴于下面的代码,方法foo应该将操作符与给定参数bar进行比较lowerBoundupperBound相同的抽象类型Bar

trait Foo {
  type Bar <: Ordered[Bar]
  val lowerBound: Bar
  val upperBound: Bar
  def foo(bar: Bar) = bar >= lowerBound && bar <= upperBound
}

这样可以定义特征Foo。问题从下面的具体类FooImpl开始。

class FooImpl extends Foo {
  type Bar = Int
  val lowerBound = 0
  val upperBound = 5
}

我了解scala.Int没有实现scala.runtime.RichInt所做的,有效scala.math.Ordered[Int]。将类型Bar定义为RichInt代替它不起作用,因为它不符合scala.math.Ordered[RichInt]。我第三次尝试将Bar类型定义为Ordered[Ord],其中Ord被声明为type Ord并在FooImpl中将其定义为Int也无法正常工作

可能接近的解决方案如何?

1 个答案:

答案 0 :(得分:8)

可能有更优雅的解决方案,但您可以通过将类型限制移到方法而不是类型声明来实现此目的:

trait Foo {
  type Bar
  val lowerBound: Bar
  val upperBound: Bar
  def foo(bar: Bar)(implicit ev: Bar => Ordered[Bar]) = {
    bar >= lowerBound && bar <= upperBound
  }
}

然后你的FooImpl就像你拥有它一样:

class FooImpl extends Foo {
  type Bar = Int
  val lowerBound = 0
  val upperBound = 5
}

来自REPL:

scala> new FooImpl()
res0: FooImpl = FooImpl@2dbbec72

scala> res0.foo(3)
res1: Boolean = true

scala> res0.foo(7)
res2: Boolean = false

这里的缺点是可以使用无序类型扩展特征(尽管在这种情况下无法调用foo):

class A // not Ordered

class BrokenFoo extends Foo {
  type Bar = A
  val lowerBound = new A
  val upperBound = new A
} // compiles

new BrokenFoo().foo(new A) // doesn't compile

或者,您可以将要求保持在班级级别(因此阻止任何人创建BrokenFoo),如下所示,但FooImpl必须略有改变:

trait Foo {
  type Bar
  implicit val baz: Bar => Ordered[Bar]
  val lowerBound: Bar
  val upperBound: Bar
  def foo(bar: Bar) = { bar >= lowerBound && bar <= upperBound }
}

class FooImpl extends Foo {
  type Bar = Int
  val baz = implicitly[Bar => Ordered[Bar]]
  val lowerBound = 0
  val upperBound = 5
}

此问题感觉view or context bounds应该适用,但不幸的是,您似乎无法在type声明或特征上的泛型类型参数中使用它们。