определить метод для возврата типа класса, расширяющего его - PullRequest
21 голосов
/ 17 марта 2011

Я хотел бы иметь возможность сделать что-то вроде этого:

trait A {
  def f(): ???_THE_EXTENDING CLASS
}
class C extends A {
  def f() = self
}
class D extends A {
  def f() = new D
}
class Z extends D {
  def f() = new Z
}

И следующее не скомпилируется, учитывая код выше

class Bad1 extends A {
  def f() = "unrelated string"
}
class Bad2 extends A {
  def f() = new C // this means that you can't just define a type parameter on
                  // A like A[T <: A] with f() defined as f: T
}
class Bad3 extends D // f() now doesn't return the correct type

Есть ли название для такого рода отношений? И как это аннотировано / реализовано в Scala?

Редактировать

Как видите, работает следующий вид:

scala> trait A {
     | def f: this.type 
     | }
defined trait A

scala> class C extends A {
     | def f = this 
     | }
defined class C

scala> class D extends A {
     | def f = new D
     | }
<console>:7: error: type mismatch;
 found   : D
 required: D.this.type
       def f = new D
               ^

Есть ли способ обойти это?

Редактировать 2

Используя вторую систему, я могу сделать это, что хорошо для определения класса D:

scala> trait A[T <: A[T]] { def f(): T }
defined trait A
// OR
scala> trait A[T <: A[T]] { self: T =>
     | def f(): T
     | }

scala> class C extends A[C] { def f() = new C }
defined class C

scala> class D extends C
defined class D

scala> (new D).f
res0: C = C@465fadce

Ответы [ 3 ]

14 голосов
/ 17 марта 2011

Боюсь, что нет никакой возможности узнать, что такое расширенный класс из расширяющего класса.

Наиболее близким к тому, что вы хотели бы иметь, является что-то похожее на шаблон Curily Recurring Template Pattern (CRTP)хорошо известно из C ++.

trait A[T <: A[T]] {
  def f(): T;
}

class C extends A[C] {
  def f() = new C
}

class D extends A[D] {
  def f() = new D
}
6 голосов
/ 17 марта 2011

Одна вещь, которую вы можете сделать, это вернуть тип this.type:

trait A {
  def f(): this.type
}

class C extends A {
  def f() = this
}

class D extends A {
  def f() = this
}

class Z extends D {
  override def f() = this
  def x = "x"
}

println((new Z).f().x)

Это может быть полезно для строителей.

4 голосов
/ 17 марта 2011

Вот еще одно возможное решение.Это комбинация типа self + параметр типа:

trait A[T <: A[T]] { self: T =>
  def f(): T
}

class Z extends A[Z] {
  override def f() = new Z
  def x = "x"
}

println((new Z).f().x)

Здесь вы можете найти дополнительную информацию об этом решении:

scala self-type: значение не является ошибкой члена

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