В следующем коде показана поверхностная иерархия, в которой тип, представляющий обобщенную двоичную операцию, используется для обоснования параметризованного абстрактного типа в другой иерархии поверхностного контейнера:
trait BinaryOp[A] extends ((A,A) => A)
trait Plus[A] extends BinaryOp[A]
trait Minus[A] extends BinaryOp[A]
trait BaseOps {
type T[A] <: BinaryOp[A]
def apply[B](one: B, two: B)(op: T[B]) = op(one, two)
}
case object PlusOp extends BaseOps {
override type T[A] = Plus[A]
}
case object MinusOp extends BaseOps {
override type T[A] = Minus[A]
}
object App {
val plus = new Plus[Int] {
def apply(i: Int, i2: Int) = i + i2
}
def main(a: Array[String]) {
val exp = Expr(PlusOp)
exp.bo(1,2)(plus)
}
}
Идея состоит в том, чтобы иметь возможность заранее указать операцию, которая может быть допустимой для многих различных типов, без привязки к операции, специфичной для типа. Если я определю класс выражения в общем, все хорошо
case class Expr[T <: BaseOps](bo: T = PlusOp)
Однако для моего случая использования нежелательно, чтобы Expr был перекалиброван:
case class Expr(bo: BaseOps = PlusOp)
Следующий код не работает без универсального Expr:
object App {
val plus = new Plus[Int] {
def apply(i: Int, i2: Int) = i + i2
}
def main(a: Array[String]) {
val exp = Expr(PlusOp)
exp.bo(1,2)(plus)
}
}
Ошибка:
found : App.plus.type (with underlying type java.lang.Object with Plus[Int])
required: exp.bo.T[Int]
exp.bo(1,2)(plus)
Это создает впечатление, что информация о типе из абстрактного типа T[A] <: BinaryOp[A]
не подтверждается информацией из подтипа PlusOp
, который переопределяет абстрактный тип как T[A] = Plus[A]
. Есть ли способ обойти это, не делая Expr
универсальным?