Типы возвращаемых значений для нереализованных методов в типажах

Предположим, у меня есть трейт SomeTrait с нереализованным методом func. Этот метод вернет что-то, что расширяет SomeTrait. Другими словами, у меня есть что-то вроде следующего:

trait SomeTrait
{
  def func(x: Int): SomeTrait
}

Теперь я реализую класс ExtensionClass, который расширяет SomeTrait, и оказывается, что на самом деле я хочу, чтобы реализация func в этом классе возвращала объект типа ExtensionClass:

class ExtensionClass(val param: String) extends SomeTrait
{
  override def func(x: Int): SomeTrait = return new ExtensionClass("test")

  // ExtensionClass also defines another method not specified in SomeTrait
  def anotherMethod: String = return param ++ "!"
}

Пока все вышеперечисленное работает хорошо. Проблема возникает, если я хочу вызвать anotherMethod для объекта, возвращаемого func, вот так:

val extension = new ExtensionClass("hello")
extension.func(5).anotherMethod

Система типов распознает только то, что объект, заданный extension.func(5), имеет тип SomeTrait, поэтому anotherMethod не виден. Это подводит нас к моему вопросу:

Вопрос. Можно ли сделать так, чтобы описанное выше работало без явного приведения/сопоставления с образцом для результата func? Например, могу ли я обновить сигнатуру типа func в SomeTrait, чтобы можно было сделать какой-то вывод типа? Любая помощь будет оценена.


person providence    schedule 18.06.2014    source источник


Ответы (1)


Вы можете добавить общий параметр:

trait SomeTrait[T <: SomeTrait[T]] {
    def func(x: Int): T
}

class ExtensionClass(val param: String) extends SomeTrait[ExtensionClass] {
    def func(x: Int) = new ExtensionClass("test")
    def anotherMethod: String = param ++ "!"
}

в качестве альтернативы вы можете добавить элемент абстрактного типа:

trait SomeTrait {
    type T <: SomeTrait
    def func(x: Int): T
}

class ExtensionClass(val s: String) extends SomeTrait {
    type T = ExtensionClass
    def func(x: Int) = new ExtensionClass("test")
    def anotherMethod: String = s ++ "!"
}
person Lee    schedule 18.06.2014
comment
Кажется, что T означает разные вещи по обе стороны от <: в T <: SomeTrait[T]. Так ли это? Если да, то что именно происходит? - person providence; 19.06.2014
comment
@providence - Нет, T одинаков с обеих сторон, например. ExtensionClass является подтипом SomeTrait[ExtensionClass]. Это называется шаблоном повторяющегося шаблона и является распространенным подходом к достижению такого рода статического полиморфизма в иерархиях объектов. См., например, Enum в Java. - person Lee; 19.06.2014
comment
И если бы я хотел явно указать тип возврата func в реализации, что бы мне нужно было написать? то есть в def func(x: Int): ? = new ExtensionClass("test") что заменяет ? - person providence; 19.06.2014
comment
@providence - func возвращает T, а T в примере равно ExtensionClass. - person Lee; 19.06.2014