2017-04-12 5 views
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 
+1

型崩れは間違いなくこれを行うことができ、http://stackoverflow.com/questions/23192760/safely-copying-fields-between-case-classes-of-different-types –

+0

おかげで、このルックスを見て有望な – Sofia

答えて

3

まずvalとしてtraitメンバーを定義することはありません:あなたは例えば、暗黙的な変換を使用することを行うことができます

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

です。実際には 'gen2 to(gen from obj)'でコンパイルされません。 – Sofia

+0

また、 "traitメンバをval後の時点で実施される」と述べた。 - ちょっと凝って、関連するリンクを教えてもらえますか?ありがとう:) – Sofia

+1

@ソフィアhttp://stackoverflow.com/questions/19642053/when-to-use-valor-def-in-scala-traits。私は私の答えを更新しました。 – flavian

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 paramsをうまくapplyの一部としてマスクされているので、これは少し良いです。

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

この行は、genT from align(genS to s)です。

  • まずgenS to sフィールド情報とHList例えば、LabelledGenericSourceインスタンスに変換します。

  • アラインメントは、Targetタイプに一致するように、Sourceタイプのために作成されたHListのタイプとフィールドを整列します。

  • genT from ..

    は、私たちは私たちがすでにAlignを持っているものですコンパイラはフィールドや種類は「すべてそこに」ある「ことを証明」することができます付与HListからTargetのインスタンスを作成することができます。

+0

はい、私は知っています。私が避けようとしているこれらの変換関数を作成するのは、 – Sofia

関連する問題