Проблема параметризованного типа Scala с возвратом экземпляра того же типа

Далее я представлю только очень сокращенные версии моего кода Scala. Достаточно, чтобы показать проблему. Ненужные блоки кода будут сокращены до ... .

Работающая часть

Я создал векторную библиотеку (то есть для моделирования математических векторов, а не векторов в смысле scala.collection.Vector ). Основная черта выглядит так:

trait Vec[C] extends Product {
  def -(o:Vec[C]):Vec[C] = ...
  ...
}

Я создал множество подтипов для определенных векторов, например, Vec2 для двумерных векторов или Vec2Int , специализированный для двумерных векторов Int .

Подтипы сужают типы возвращаемых данных некоторых операций. Например, вычитание Vec2Int из другого вектора вернет не общий Vec [Int] , а более конкретный Vec2Int .

Кроме того, у меня есть объявили эти методы в очень специфических подтипах, таких как Vec2Int как final , тем самым позволяя компилятору выбирать эти методы для встраивания.

Это работает очень хорошо, и я создал быстрый и полезная библиотека для векторных вычислений.

Опираясь на это, теперь я хочу создать набор типов для моделирования основных геометрических форм. Основная черта формы выглядит так:

trait Shape[C, V <: Vec[C]] extends (V=>Boolean) {
  def boundingBox:Box[C,V]
}

Где Box будет подтипом Shape , моделирующим n-мерный блок.

Часть, которая не работает

Теперь я попытался определить box :

trait Box[C, V <: Vec[C]] extends Shape[C,V] {
  def lowCorner:V
  def highCorner:V
  def boundingBox = this
  def diagonal:V = highCorner - lowCorner // does not compile
}

Метод диагональ не компилируется, потому что метод Vec .- возвращает Vec [C] , а не V .

Конечно, я мог бы заставить диагональ возвращать Vec [C] , но это было бы во многих отношениях неприемлемым. На этот раз я потеряю оптимизацию компилятора для конкретных подтипов Vec . Кроме того, если у вас, например, есть прямоугольник, описанный двумя двумерными векторами Float ( Vec2Float ), имеет смысл предположить, что диагональ также является Vec2Float . Я не хочу потерять эту информацию.

Моя попытка решить проблему

Следуя примеру иерархии коллекций Scala, я ввел тип VecLike :

trait VecLike[C, +This <: VecLike[C,This] with Vec[C]] {
  def -(o:Vec[C]):This
  ...
}

и сделал Vec его расширением:

trait Vec[C] extends Product with VecLike[C, Vec[C]] ...

(затем я бы перешел к созданию более конкретных подтипов VecLike , например Vec2Like или Vec3Like , чтобы сопровождать мою иерархию Vec ] типов.)

Теперь новое определение для Shape и Box выглядит так:

trait Shape[C, V <: VecLike[C,V] with Vec[C]] ...

trait Box[C, V <: VecLike[C,V] with Vec[C]] extends Shape[C,V] {
  ...
  def diagonal:V = highCorner - lowCorner 
}

Тем не менее, компилятор жалуется:

Error: type mismatch;
found: Vec[C]
required: V

Это меня смущает. Тип VecLike явно возвращает This в минус-методе, который переводится в параметр типа V типа Box . Я вижу, что метод минус Vec по-прежнему возвращает Vec [C] , но почему на данном этапе компилятор не может использовать возвращаемый тип метода минус VecLike ?

Как я могу исправить эту проблему?

5
задан Madoc 23 February 2011 в 23:59
поделиться