Scala: копирование общего класса case в другой

У меня есть следующая настройка, где я хочу скопировать экземпляр baseData в экземпляр 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

Итак, копируем myData в otherData ниже:

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

даст: moreData1(1,1,"C","abcd").

Для этого я хочу использовать функцию со следующей сигнатурой, потому что у меня будет более одного класса case, расширяющего как baseData, так и moreData:

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

Я уверен, что вы можете сделать это с помощью Shapeless. , но не понял как. Примеры есть (здесь) при копировании классов case, расширяющих ту же черту, и других (здесь), сопоставление значений между различными классами case через универсальное представление. Но я не понял, как использовать LabelledGeneric с аргументами, ограниченными типажами, переданными в copyOver. Я также не хочу жестко кодировать дополнительные поля в otherData, которых нет в myData.

Я ищу полностью общую реализацию. Любые идеи?


person Cigogne Eveillée    schedule 15.07.2016    source источник


Ответы (1)


Вы должны иметь возможность использовать класс типа UpdateRepr из ваш первый бесформенный пример.

Вы можете определить copyOver с помощью UpdateRepr следующим образом:

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))

Который вы можете использовать следующим образом:

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

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

Обратите внимание, что у вас могут возникнуть проблемы с SI-7046 из-за производного класса типа запечатанного признака (совместного продукта) для UpdateRepr, который вы могли заметить в REPL или при разделении UpdateRepr и запечатанных признаков по нескольким файлам.

person Peter Neyens    schedule 16.07.2016
comment
Спасибо, супер полезно! Последнее препятствие заключается в том, что я получаю следующую ошибку компиляции: could not find implicit value for parameter update: cmd23.UpdateRepr[cmd19.moreData1,R] copyOver(myData, otherData) при вызове copyOver. Есть идеи, почему? - person Cigogne Eveillée; 16.07.2016
comment
Если вы пробуете REPL, попробуйте использовать Ctrl + P с запечатанными трейтами, классами case и UpdateRepr за один раз. - person Peter Neyens; 16.07.2016
comment
Ах, да, это работает при копировании всего за один раз в режиме вставки. Спасибо! Последний вопрос: если я правильно понимаю UpdateRepr, baseData должно быть точным подмножеством moreData, чтобы это работало. Значение baseData не может иметь ни одного поля, отсутствующего в moreData. Вы согласны? - person Cigogne Eveillée; 17.07.2016