Scala案例类转换

时间:2017-04-12 13:53:19

标签: scala type-conversion

有没有办法将一个案例类转换为另一个案例类,当它们具有相同的字段并从相同的特征继承而不提供转换器函数(这只会执行一对一的字段映射)?

例如:

trait UberSomething {
  val name: String
}
// these may be located in different files
case class Something(name: String) extends UberSomething
case class SomethingOther(name: String) extends UberSomething

val s = Something("wtv")
//s.asInstanceOf[SomethingOther] FAILS

2 个答案:

答案 0 :(得分:3)

首先,如果trait成员要在稍后实施,则永远不要将val成员定义为<{1}}。

trait UberSomething {
  def name: String
}
// these maybe in different files
case class Something(name: String) extends UberSomething
case class SomethingOther(name: String) extends UberSomething

import shapeless._, ops.hlist.Align

我之前在Stackoverflow上看到过的另一种方法,就是窃取街头信誉的道歉,就是使用Align这样的字段顺序并不重要。

class Convert[Target] {
  def apply[Source, HLS <: HList, HLT <: HList](s: Source)(implicit

    // Convert the Source to an HList type
    // include field names, e.g "labelled"
    // Shapeless "generates" this using an implicit macro
    // it looks at our type, extracts a list of (Name, Type) pairs
    genS: LabelledGeneric.Aux[Source, HLS],

    // Convert the Target o an HList type
    // include field names, e.g "labelled"
    // So again we have a (Name, Type) list of pairs this time for Target
    genT: LabelledGeneric.Aux[Target, HLT],

    // Use an implicit align to make sure the two HLists
    // contain the same set of (Name, Type) pairs in arbitrary order.
    align: Align[HLS, HLT]
  ) = genT from align(genS to s)
}
// Small trick to guarantee conversion only requires
// a single type argument, otherwise we'd have to put something
// in place for HLS and HLT, which are meant to be path dependant
// and "calculated" by the LabelledGeneric.Repr macro so it wouldn't work as it breaches the "Aux pattern", which exposes a type member materialized by a macro in this case.
// HLT and HLS come from within genS.Repr and genT.Repr.
def convert[T] = new Convert[T]

这有点好,因为HList参数很好地掩盖了apply的一部分,所以你不会绊倒自己。

val sample = Something("bla")
convert[SomethingOther](sample) // SomethingOther("bla")

让我们回顾一下这一行:genT from align(genS to s)

  • 首先genS to sSource个实例转换为LabelledGeneric,例如HList的字段信息。

  • 对齐HList类型的已创建Source的类型和字段,以匹配Target类型。

  • genT from ..允许我们从Target创建HList的实例,授予编译器可以&#34;证明&#34;字段和类型是&#34;所有&#34;,这是Align已经存在的内容。

答案 1 :(得分:1)

您可以使用隐式转换来实现,例如:

trait UberSomething {
  val name: String
}

case class Something(name: String) extends UberSomething
case class SomethingOther(name: String) extends UberSomething

object Something {
  implicit def somethingToSomethingOther(s:Something):SomethingOther = SomethingOther(s.name)
}
object SomethingOther {
  implicit def somethingOtherToSomething(s:SomethingOther):Something = Something(s.name)
}

val s = Something("wtv")
val so:SomethingOther = s