2017-04-12 120 views
1

有没有办法将一个案件类转换为另一种情况下,当他们有相同的领域,并从相同的特质继承,而不提供转换器功能(这只会做一对一的字段映射)?斯卡拉案例类转换

例如:

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 
+1

无形绝对可以做到这一点,看看http://stackoverflow.com/questions/23192760/safely-copying-fields-between-case-classes-of-different-types –

+0

谢谢,这看起来很有希望 – Sofia

回答

3

首先从未定义trait成员val如果他们是为了在以后得以实施点。

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 

另一种方法我在什么地方#2见过,所以道歉偷街头信誉,是使用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 PARAMS是很好的掩盖作为apply一部分,所以你不要自己绊倒了。

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

我们来看看这一行:genT from align(genS to s)

  • 首先genS to sSource实例转换为LabelledGeneric,e.g一个HList与现场信息。

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

  • genT from ..允许我们从授予的编译器可以“证明”的字段和类型为“所有有”一个HList,这是我们已经有了Align创建Target一个实例。

+0

这实际上并没有在'gen2中编译为(gen from obj)' – Sofia

+0

另外,“从来没有将特征成员定义为val,如果它们意味着以后再实施“。 - 你能详细说明一下,还是指向相关链接?谢谢:) – Sofia

+1

@Sofia http://stackoverflow.com/questions/19642053/when-to-use-val-or-def-in-scala-traits。我已经更新了我的答案。 – flavian

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 
+0

是的,我知道。创建这些转换函数(隐式或不)是我试图避免的。 – Sofia