繁体   English   中英

Scala:父类有没有办法访问仅由子节点定义的方法?

[英]Scala: Is there a way for a parent class to access methods defined only by children?

我有两个从抽象基类继承的case类。 我想在抽象基类上定义一些方法,这些方法在继承case类上使用复制方法(因此返回子类的实例。)有没有办法使用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) = {
    ...
  }
}

由于这个问题,我已经想出如何得到我想要的结果: 如何使用Scala的这种类型,抽象类型等来实现Self类型? 但它涉及向BaseClass添加一个makeCopy方法,并通过在每个子案例类中调用复制来覆盖它,并且语法(特别是对于Self类型)相当混乱。 有没有办法用Scala的内置自键型来做到这一点?

你无法做你想做的事,因为copy 需要知道所有可能的参数 因此,即使从Copyable继承的case类,它也不是你需要的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级别setB(b0: Int): BaseBase或者只是忘记类型参数化并使用BaseClass作为返回类型(但是要认识到HasC不能使用BaseClass方法并且仍然保留其类型标识)。

我觉得你运气不好。 HasCHasD上的copy方法具有不同的签名。 由于默认参数,它有点隐藏,但基本上BaseClass的定义不知道要调用哪个copy方法。

你可以在抽象类中定义一个makeCopy,它接受一个复制器函数,它接受Unit并返回一个BaseClass,然后,在你使用它的方法(如doubleB)中覆盖它们在case类体中,并通过传递它来使用makeCopy匿名函数,用于更改道具创建新副本的工作,如下所示:

package delegatedcopy

abstract class BaseClass(a: String, b:Int){
  def aField = a
  def bField = b
  def doubleB:BaseClass
  def makeCopy(copier: () => BaseClass):BaseClass = copier()
}

case class HasC(override val aField: String, override val bField: Int, cField: Boolean) extends BaseClass(aField, bField){
  override def doubleB:BaseClass = makeCopy( ()=> HasC(aField, bField * 2, cField) )
}

case class HasD(override val aField: String, override val bField: Int, dField:Double) extends BaseClass(aField, bField){
  override def doubleB:BaseClass = makeCopy( ()=> HasD(aField, bField * 2, dField) )
}

一个演示它的测试应用程序:

import delegatedcopy._

object TestApp extends Application{
  val hasC = HasC( "A C object", 5, true)
  val hasD = HasD( "A D object", 2, 3.55)
  val hasCDoubleB = hasC.doubleB
  val hasDDoubleB = hasD.doubleB

  println(hasC) // prints HasC(A C object,5,true)
  println(hasCDoubleB) //prints HasC(A C object,10,true)

  println( hasD ) // prints HasD(A D object,2,3.55)
  println( hasDDoubleB ) // prints HasD(A D object,4,3.55)
}

通过这种方式,您可以使所有子类的makeCopy方法与基类保持一致,并且可以在基类和案例类中实现或混合相当多的功能,同时将公共代码保存在安全的位置并能够在特定案例类中传递客户端BaseClass和模式匹配。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM