我有两个从抽象基类继承的案例类。我想在抽象基类上定义一些方法,这些方法在继承的case类上使用copy方法(并因此返回子类的实例。)是否可以使用self类型来做到这一点?
示例代码:
abstract class BaseClass(a: String, b: Int) {
this: case class => //not legal, but I'm looking for something similar
def doubleB(newB: Int) = this.copy(b = b * 2) //doesn't work because BaseClass has no copy
}
case class HasC(a: String, b: Int, c: Boolean) extends BaseClass(a, b) {
def doesStuffWithC(newC: Boolean) = {
...
}
}
case class HasD(a: String, b: Int, D: Double) extends BaseClass(a, b) {
def doesStuffWithD(newD: Double) = {
...
}
}
由于这个问题,我已经弄清楚了如何获得想要的结果:
How to use Scala's this typing, abstract types, etc. to implement a Self type?
但是它涉及到在BaseClass中添加一个makeCopy方法,并在每个子case类中调用复制来覆盖它,并且语法(尤其是Self类型)尤其令人困惑。使用Scala的内置自动键入功能可以做到这一点吗?
最佳答案
您无法做您想做的事情,因为copy
需要知道所有可能的参数。因此,即使案例类是从Copyable
继承的,也不是您需要的copy
。另外,如果您要保持类型的笔直,则会因Scala缺少“MyType
”而受挫。因此,您不能只扩展基类。但是,您可以添加一个抽象方法并键入批注:
abstract class BaseClass[C <: BaseClass[_]](a: String, b: Int) {
def setB(b0: Int): C
def doubleB(b0: Int) = setB(b0*2)
}
case class HasC(a: String, b: Int, c: Boolean) extends BaseClass[HasC](a,b) {
def setB(b0: Int) = this.copy(b = b0)
def doesStuffWithC(c0: Boolean) = doubleB(if (c0) b else -b).copy(c = c0)
}
然后您可以:
scala> HasC("fish",1,false).doesStuffWithC(true)
res47: HasC = HasC(fish,2,true)
如果您有很多共享功能仅依赖于复制
b
的能力(很多方法或少数复杂方法),那么这项额外的工作将是值得的(也就是说,这解决了DRY问题)。相反,如果您想抽象HasC
和其他派生类,则可以使用BaseClass[_]
或添加另一个定义setB(b0: Int): BaseBase
的级别,或者干脆忘记类型参数化并将BaseClass
用作返回类型(但要意识到HasC
无法使用BaseClass
方法,并且保留其类型标识)。
关于Scala:父类是否可以访问仅由子级定义的方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10304728/