Rui*_*ves 35 scala self-type abstract-type
我需要一种方法来强制抽象类中的方法,使其具有被调用对象的具体类的返回类型.最常见的示例是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)
}
Run Code Online (Sandbox Code Playgroud)
我已经看到了许多方法,包括这个伟大答案中的方法.但是,它们都没有真正强制实现返回自己的类型.例如,以下类有效:
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, "")
}
Run Code Online (Sandbox Code Playgroud)
我可以这样做的事实导致,如果我正在做对象的副本,我所拥有的唯一信息是它们是A's 的给定子类:
// type error: Seq[A] is not a Seq[CA]!
def createCopies[CA <: A](seq: Seq[CA]): Seq[CA] = seq.map(_.copy(genNewId()))
Run Code Online (Sandbox Code Playgroud)
我能做到更好,更安全的方式吗?
编辑:如果可能的话,我希望能够创建任意深层次的抽象类层次结构.也就是说,在前面的例子中,我期望能够创建一个扩展的抽象类A2,A然后继续创建A2具体的子类.但是,如果这简化了问题(就像抽象类型的情况那样),我不需要进一步扩展已经具体的类.
EEC*_*LOR 25
我能想到的唯一解决方案就是这个:
trait CanCopy[T <: CanCopy[T]] { self: T =>
type Self >: self.type <: T
def copy(newId: Int): Self
}
abstract class A(id: Int) { self:CanCopy[_] =>
def copy(newId: Int): Self
}
Run Code Online (Sandbox Code Playgroud)
以下将编译:
class B(id: Int, x: String) extends A(id) with CanCopy[B] {
type Self = B
def copy(newId: Int) = new B(newId, x)
}
class C(id: Int, y: String, z: String) extends A(id) with CanCopy[C] {
type Self = C
def copy(newId: Int) = new C(newId, y, z)
}
Run Code Online (Sandbox Code Playgroud)
以下内容无法编译:
class D(id: Int, w: String) extends A(id) with CanCopy[D] {
type Self = A
def copy(newId: Int) = new D(newId, w) // returns an A
}
class E(id: Int, v: String) extends A(id) with CanCopy[E] {
type Self = B
def copy(newId: Int) = new B(newId, "")
}
Run Code Online (Sandbox Code Playgroud)
我实际上忘了删除复制方法.这可能更通用一些:
trait StrictSelf[T <: StrictSelf[T]] { self: T =>
type Self >: self.type <: T
}
abstract class A(id: Int) { self:StrictSelf[_] =>
def copy(newId:Int):Self
}
Run Code Online (Sandbox Code Playgroud)
不要在声明端强制进行类型绑定,除非您需要在itelf的定义中进行该绑定A。以下内容就足够了:
abstract class A(id: Int) {
type Self
def copy(newId: Int): Self
}
Run Code Online (Sandbox Code Playgroud)
现在Self在使用站点上强制使用该类型:
def genNewId(): Int = ???
def createCopies[A1 <: A { type Self = A1 }](seq: Seq[A1]): Seq[A1] =
seq.map(_.copy(genNewId()))
Run Code Online (Sandbox Code Playgroud)