给定下面的代码,方法foo应该比较操作符给定的参数条与lowerBound和upperBound都是相同的抽象类型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被声明为Ord类型并在FooImpl中将其定义为Int也不起作用.
一个可能接近的解决方案怎么样?
解决方法
可能有一个更优雅的解决方案,但您可以通过将类型的限制移动到方法而不是类型声明来实现此目的:
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应该适用,但不幸的是,你似乎不能在类型声明或特征上的泛型类型参数中使用它们.