переопределить функцию в признаке - PullRequest
5 голосов
/ 23 августа 2011

Допустим, у меня есть следующая черта

trait Foo[T] {
  def overrideMe(other:Foo[T]) : Int
}

Я бы хотел иметь возможность

class Bar extends Foo[Int] {
   override  def overrideMe(other:Bar) : Int = other.BarFn
}

, но она не компилируется.Причина в том, что я бы хотел, чтобы overrideMe мог использовать функциональность подтипа.Я мог бы сделать что-то вроде

class Bar extends Foo[Int] {
   override  def overrideMe(other:Foo[Int]) : Int = {
      other.asInstanceOf[Bar].BarFn
}

, но это выглядит не очень хорошо.

Можно ли сказать, что виртуальная функция может быть переопределена подтипом?

edit @agilesteel Это почти работает, но у меня возникают проблемы, если у меня есть функция в другом классе, полагающаяся только на черту Foo

class Test[T] {
    def callOverrideMe(a : Foo[T], b : Foo[T] ) : Int = a.overrideMe(b)
}

Я получаю ошибку компиляции: несоответствие типов;найдено b.type (с базовым типом foo.Foo [T]) требуется a.SubType

Ответы [ 3 ]

7 голосов
/ 23 августа 2011
trait Foo[T] {
  type TheSubType <: Foo[T]
  def overrideMe(other: TheSubType) : Int
}

class Bar extends Foo[Int] {
   type TheSubType = Bar
   override def overrideMe(other: Bar) : Int = other.barFn
   def barFn = 10
}
6 голосов
/ 23 августа 2011
class Test[T] {
    def callOverrideMe(a : Foo[T], b : Foo[T] ) : Int = a.overrideMe(b)
}

Конечно, вы не можете заставить его работать с этой подписью. Просто подумай

class Baz extends Foo[Int] {...}

new Test[Int].callOverrideMe(new Bar, new Baz)

Это должно быть то же самое, что и new Bar.overrideMe(new Baz), но вы не хотите, чтобы оно компилировалось!

Вы можете использовать любопытно повторяющийся шаблон для этого:

trait Foo[T, Sub <: Foo[T, Sub]] {
  def overrideMe(other:Sub) : Int
}

class Bar extends Foo[Int, Bar] {
   override def overrideMe(other:Bar) : Int = other.BarFn
}

class Test[T] {
    def callOverrideMe[Sub <: Foo[T, Sub]](a : Sub, b : Sub) : Int = a.overrideMe(b)
}

То, что я пытаюсь выполнить, - это алгоритм, основанный на признаке, и затем некоторые функции реализованы в подтипах. Есть ли другой хороший шаблон дизайна для этого?

Проверьте классы типа Скалаз. Например. https://github.com/scalaz/scalaz/blob/master/core/src/main/scala/scalaz/Equal.scala

4 голосов
/ 23 августа 2011

Для второй части вашего вопроса, решение agilesteel может работать с уточнением типа,

trait Foo[T] {
  type R <: Foo[T]
  def overrideMe(other: R) : Int
}

class Bar extends Foo[Int] {
  type R = Bar
  override def overrideMe(other: Bar) : Int = other.barFn
  def barFn = 10
}

def callOverrideMe[T, R0 <: Foo[T]{type R = R0}](a : R0, b : R0) : Int = {
  a.overrideMe(b)
}

Могут возникнуть сложности с выводом типа T в callOverrideMe. Чтобы улучшить вывод типа, нужно сделать R более привязанным, т.е. дать ему собственный параметр типа T.

Это решение в основном эквивалентно решению Алексея Романова и демонстрирует, как абстрактные типы могут отображаться как параметры типов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...