Scala案例类继承与代码可重用性

时间:2015-12-11 15:02:03

标签: scala inheritance

我正在尝试在case类中建模我的类层次结构。我感谢相关的discussion about duplication of case class properties here

考虑下面显示的类层次结构。

trait Super {
  def a:String
}

case class Child1(a:String, b:String) extends Super {
  override def toString = s" a = $a, b= $b"

}

case class Child2(a:String, c:String) extends Super {
  override def toString = s" a = $a, c= $c"
}

我有一个场景,我想使用abc等基本属性构建案例类对象,以及使用XML。我为这些案例类创建了伴随对象,如下所示。

object Child1 {    
   def apply(node: scala.xml.Node): Child1 = {
      val a = (node \ "a").text
      val b = (node \ "b").text
      Child1(a, b)
  }
}


object Child2 {
    def apply(node: scala.xml.Node): Child2 = {
      val a = (node \ "a").text
      val c = (node \ "c").text
      Child2(a, c)
  }
}

在上面的代码中,我必须复制解析a - (node \ "a").text值的行。即使我将Super转换为abstract超类,似乎也没有办法做同样的事情。

我想知道如何做到这一点,我可以使用Java中Super类中的抽象类和几个构造函数轻松完成。

UPDATE:scala.xml.Node类型的合格名称。

3 个答案:

答案 0 :(得分:1)

事实上,对于案例类来说,这是不可能的。你必须定义一个帮助器来摆脱这样的重复。

Child1(Super.getAValue(node), c)

答案 1 :(得分:1)

scala.macrosshapeless

这是一项微不足道的任务

让我们定义通用的xml提取器

import scala.xml.Node

trait Extract[L] extends (scala.xml.Node => L)

对于仅包含HList record s的字符串的简单实现:

import shapeless._
import shapeless.labelled._

implicit object extractHNil extends Extract[HNil] {
  def apply(node: Node): HNil = HNil
}

implicit def extractHCons[K <: Symbol, L <: HList]
(implicit witness: Witness.Aux[K], recur: Extract[L]) =
  new Extract[FieldType[K, String] :: L] {
    def apply(node: Node): ::[FieldType[K, String], L] = {
      val name = witness.value.name
      val value = (node \ name).text
      field[K](value) :: recur(node)
    }
  }

现在,您可以在LabelledGeneric

之上构建案例类提取器构建
implicit def extractCase[C, L]
(implicit lgen: LabelledGeneric.Aux[C, L], extract: Extract[L]) =
  new Extract[C] {
    def apply(node: Node): C = lgen.from(extract(node))
  }

从这一点开始,您可以为同伴添加简单的mixin:

abstract trait XmlReader[C] {
  def extract: Extract[C]
  def apply(node: scala.xml.Node) = extract(node)
}

将您的构建器实现为

object Child1 extends XmlReader[Child1] {
  val extract: Extract[Child1] = implicitly
}

object Child2 extends XmlReader[Child2] {
  val extract: Extract[Child2] = implicitly
}

现在您可以验证它:

val node = <node>
  <a>1</a>
  <b>2</b>
  <c>3</c>
</node>

println(Child1(node)) // a = 1, b= 2
println(Child2(node)) // a = 1, c= 3

请注意,扩展此类解析器并不是一项非常艰巨的任务,几乎可以通过密封的case类系列来定义。请参阅picopickle作为使用无形

构建的通用解析器的示例

答案 2 :(得分:0)

定义方法superA做到

import scala.reflect.runtime.universe._

trait Super {
  def a: String
}

trait Node {
  def \(s: String): String = s
}

object Node {
  // also you can move it to Super companion object 
  implicit class SuperMethodA(val node: Node) {
    def superA = node \ "a"
  }

}

case class Child1(a: String, b: String) extends Super {
  override def toString = s" a = $a, b= $b"

}
object Child1{
  def apply(node: Node): Child1 = {
    val a = node.superA //.text
    val b = (node \ "b") //.text
    Child1(a, b)
  }
}

case class Child2(a: String, c: String) extends Super {
  override def toString = s" a = $a, c= $c"


}
object Child2{
  def apply(node: Node): Child2 = {
    val a = node.superA //.text
    val c = (node \ "c") //.text
    Child2(a, c)
  }
}