Как конвертировать между классами case с «в основном одинаковыми» полями с помощью Scala Shapeless

Здесь я должен рассматривать классы, которые имеют в основном одни и те же поля.

  final case class Id(id: String) // Param Class
  final case class Age(id: Id, age: Int) // Param Class

  final case class A(id: Id, data: Map[String, Any], age: Age) extends Presentable[A, APre] // Main Class 1
  final case class APre(id: String, data: Map[String, Any], age: Int) // Main Class 2

Здесь A и APre — мои основные классы.

Теперь я хочу преобразовать эти два класса с помощью Shapeless, поэтому я пишу следующую псевдофункцию:

trait Presentable[E, P] {
  def makePresentation[ET <: HList, PT <: HList](entity: E)(func : ET => PT)(implicit entGen: LabelledGeneric.Aux[E, ET], preGen: LabelledGeneric.Aux[P, PT]): P = {
    val entList = entGen.to(entity)
    preGen.from(func(entList))
  }
}

Здесь func — это преобразователь, отображающий HList из A в HList из APre (или наоборот).

И я хочу использовать такую ​​функцию:

  val age = Age(Id("age_1"), 18)
  val a = A(Id("id"), Map("tag1" -> "value1", "tag2" -> "value2"), age)

  val pre = a.makePresentation { entList =>
    entList.updateWith('id)((id: Id) => id.id).updateWith('age)((a: Age) => a.age)
  }

Здесь я могу сам подразумевать функцию отображения. Поэтому я могу преобразовать любые два класса case

Итак, вопросы: 1. Как я могу преобразовать эти два класса, используя shapeless? 2. На самом деле у меня есть куча пар классов от A до APre. Итак, я хочу, чтобы trait извлекал эту функцию преобразования, используя универсальный. Как написать эту функцию?


person Ukonn Ra    schedule 02.08.2019    source источник
comment
Я думаю, вы хотите взглянуть на Chimney scalalandio.github.io/chimney   -  person Thilo    schedule 02.08.2019


Ответы (1)


Отказ от ответственности: я являюсь одним из авторов chimney.

В более ранних выпусках chimney мы реализовали именно то, о чем вы спрашиваете - преобразование между в основном идентичные классы корпусов с использованием бесформенных.

Я бы не рекомендовал писать его вручную, так как есть некоторые краеугольные случаи, которые следует учитывать (создание значений, если новый объект отсутствует, преобразование полей, которые изменили тип/имя, Java Beans, классы значений и т. д.), а затем вы должны прийти с тем, как бы вы его настроили, поэтому, если вам нужно решение для бесформенных оснований, посмотрите на код из 0.1.10.

Однако, начиная с версии 0.2.0, мы переписали реализацию в макросы, так как если бы у вас были более крупные классы случаев для преобразования (например, 12 полей или более), некоторые производные могли бы вычислять несколько минут (!) без надежды на улучшение, если бы мы не отказались от некоторых случаев, которые мы поддерживать.

Если вы просто ищете способ обработки ваших преобразований, используйте новейший дымоход и закройте его.

person Mateusz Kubuszok    schedule 06.08.2019