Может быть более элегантное решение, но вы можете достичь этого, перенеся ограничение на тип в метод, а не на объявление типа:
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
не может быть вызван в этомcase):
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
}
Эта проблема выглядит так: границы представления или контекста должны быть применимы, но, к сожалению, не похоже, что вы можете использовать их либо в объявлениях type
, либо в параметрах универсального типа для признаков.