有没有办法将一个案例类转换为另一个案例类,当它们具有相同的字段并从相同的特征继承而不提供转换器函数(这只会执行一对一的字段映射)?
例如:
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
答案 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 s
将Source
个实例转换为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