Define метод для возврата типа класса, расширяющего его
Я хотел бы сделать что-то вроде этого:
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 = [email protected]
Ответы
Ответ 1
Я боюсь, что нет возможности узнать, что такое расширенный класс из расширяющегося класса.
Ближайшим к тому, что вы хотели бы иметь, является нечто похожее на Curiously Recurring Template Pattern (CRTP), хорошо известное из С++.
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
}
Ответ 2
Одна вещь, которую вы можете сделать, - вернуть тип 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)
Это может быть полезно для разработчиков.
Ответ 3
Вот еще одно возможное решение. Это сочетание параметра типа type + type:
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: значение не является ошибкой участника