Мне нужен способ принудительного применения метода в абстрактном классе, чтобы иметь возвращаемый тип конкретного класса объекта, на который он вызван. Наиболее распространенным примером является метод copy()
, и в настоящее время я использую подход, основанный на абстрактных типах:
abstract class A(id: Int) {
type Self <: A
def copy(newId: Int): Self
}
class B(id: Int, x: String) extends A(id) {
type Self = B
def copy(newId: Int) = new B(newId, x)
}
class C(id: Int, y: String, z: String) extends A(id) {
type Self = C
def copy(newId: Int) = new C(newId, y, z)
}
Я уже видел много подходов, в том числе в этот отличный ответ. Однако ни одна из них не заставляет реализацию возвращать свой собственный тип. Например, допустимы следующие классы:
class D(id: Int, w: String) extends A(id) {
type Self = A
def copy(newId: Int) = new D(newId, w) // returns an A
}
class E(id: Int, v: String) extends A(id) {
type Self = B
def copy(newId: Int) = new B(newId, "")
}
Тот факт, что я могу это сделать, приводит к тому, что если я делаю копии объектов, единственной информацией которых я являюсь, является то, что они относятся к данному подклассу A
:
// type error: Seq[A] is not a Seq[CA]!
def createCopies[CA <: A](seq: Seq[CA]): Seq[CA] = seq.map(_.copy(genNewId()))
Есть ли лучший способ, безопасный по типу, который я могу сделать?
EDIT: если возможно, я хотел бы сохранить возможность создавать произвольно глубокие иерархии абстрактных классов. То есть, в предыдущем примере я ожидаю, что смогу создать абстрактный класс A2
, который расширяет A
, а затем приступит к созданию конкретных подклассов A2
. Однако, если это упрощает проблему (как в случае с абстрактными типами), мне больше не нужно расширять уже конкретные классы.