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

Tim*_*ske 5 scala abstract-type

给出的方法下面的代码foo要比运营商明智的给定参数barlowerBoundupperBound相同的抽象类型全部为Bar.

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

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

class FooImpl extends Foo {
  type Bar = Int
  val lowerBound = 0
  val upperBound = 5
}
Run Code Online (Sandbox Code Playgroud)

据我所知,scala.Intscala.runtime.RichInt并没有有效地实现scala.math.Ordered[Int].将类型定义BarRichInt不起作用,因为它不符合scala.math.Ordered[RichInt].我第三次尝试将类型定义为声明BarOrdered[Ord]where 并将其定义为也不起作用.Ordtype OrdFooImplInt

一个可能接近的解决方案怎么样?

Mar*_*lty 8

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

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

然后你的FooImpl工作就像你拥有它:

class FooImpl extends Foo {
  type Bar = Int
  val lowerBound = 0
  val upperBound = 5
}
Run Code Online (Sandbox Code Playgroud)

来自REPL:

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

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

scala> res0.foo(7)
res2: Boolean = false
Run Code Online (Sandbox Code Playgroud)

这里的缺点是特征可以用无序类型扩展(尽管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
Run Code Online (Sandbox Code Playgroud)

或者,您可以将需求保持在类级别(因此阻止任何人创建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
}
Run Code Online (Sandbox Code Playgroud)

这个问题感觉像视图或上下文边界应该适用,但不幸的是,你似乎不能在type声明或特征上的泛型类型参数中使用它们.

  • 是的,如果OP愿意将Foo变成一个抽象类,那么'Bar'类型的成员可以被废除,Foo声明的第一行可以作为"抽象类Foo [Bar <%Ordered [Bar] ]".这可能比仅在一种方法上强制执行该关系更有效. (2认同)