Scala: Copying a generic case class into another

2019-08-22 05:01发布

I have the following setup, where I want to copy an instance of baseData into that of moreData:

sealed trait baseData {
  def weight: Int
  def priority: Int
} 

sealed trait moreData {
  def weight: Int
  def priority: Int
  def t: String
  def id: String
} 

case class data1(override val weight: Int, override val priority: Int) extends baseData 
case class moreData1 (override val weight:Int, override val priority: Int, override val t: String, override val id: String)extends moreData

So copying myData into otherData below:

val myData = data1(1,1) 
val otherData = moreData1 (2,2,"C","abcd") 

would yield: moreData1(1,1,"C","abcd").

To do this, I want to use a function with the following signature, because I will have more than one case class extending both baseData and moreData:

def copyOver[A <:baseData, B <:moreData](from: A, to: B) = {} 

I'm sure you can do this with Shapeless, but haven't figured out how. There are examples (here) on copying case classes extending a same trait, and others (here) mapping values between different case classes via generic representation. But I haven't figured out how to use LabelledGeneric with the trait-bounded arguments passed into copyOver. I also don't want to have to hardcode the extra fields in otherData that aren't present in myData.

I'm looking for a completely generic implementation. Any ideas?

1条回答
Anthone
2楼-- · 2019-08-22 05:42

You should be able to use the UpdateRepr type class from your first shapeless example.

You could define copyOver using UpdateRepr as follows :

import shapeless._

// baseData, moreData, data1, moreData1
// UpdateRepr ...

def copyOver[A <: baseData, B <: moreData, R <: HList](
  from: A,
  to: B
)(implicit 
  lgen: LabelledGeneric.Aux[A, R],
  update: UpdateRepr[B, R]
): B = update(to, lgen.to(from))

Which you could use as follows :

val myData = data1(1,1) 
val otherData = moreData1(2,2,"C","abcd") 

copyOver(myData, otherData)
// moreData1 = moreData1(1,1,C,abcd)

Note that it is possible you run into problems with SI-7046, because of the sealed trait (Coproduct) type class derivation for UpdateRepr, which you could notice in the REPL or when splitting UpdateRepr and the sealed traits over multiple files.

查看更多
登录 后发表回答