如何使用 Scala Shapeless 在具有“大部分相同”字段的 类 之间进行转换

How to convert between to case classes with `mostly the same` fields using Scala Shapeless

这里我必须区分具有大部分相同字段的 classes。

  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

这里 AAPre 是我的主要 classes.

现在我想使用 Shapeless 在这两个 class 之间进行转换,所以我编写了以下伪函数:

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是一个映射器,将AHList映射到APreHList(反之亦然)。

我想使用这样的功能:

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

这里我可以自己暗示映射函数。所以我可以转换任何两种情况 classes

所以问题是: 1. 如何使用 shapeless 转换这两个 classes? 2. 事实上,我有很多对 class,例如 AAPre。所以我想要一个 trait 使用泛型来提取这个转换函数。这个函数怎么写?

免责声明:我是chimney的作者之一。

earlier releases of chimney 中,我们完全实现了您所要求的 - 使用 shapeless 在大多数相同的情况 类 之间进行转换。

我不建议手写它,因为有一些极端情况需要考虑(如果新对象缺少一些则创建值,转换更改的字段 type/name,Java Beans, value 类, etc),然后你必须想出如何配置它,所以如果你需要 shapeless-bases 解决方案,请查看 0.1.10.

中的代码

但是,从 0.2.0 开始,我们将实现重写为宏,因为如果您有更大的情况 类 进行转换(例如 12 个字段或更多),一些推导可能会计算几分钟(!),但没有希望除非我们放弃一些我们支持的案例,否则会有改进。

如果您只是在寻找一种处理转换的方法,那么请使用最新的烟囱,收工吧。