scala - 在相同形状的两个案例类之间进行一般转换
问题描述
我有一堆案例类,它们在其他密封特征中具有相同形状的对应物(每个密封特征都用于 Akka Typed 行为中的详尽模式匹配),我想从一个版本转换为具有最少样板的下一个版本。
特征看起来像这样:
object RoutingCommands {
sealed trait Command
final case class ProtocolMsg(name: String, id: Int) extends Command
}
object ProtocolCommands {
sealed trait Command
final case class ProtocolMsg(name: String, id: Int) extends Command
}
我知道我可以shapeless.Generic
像这样进行转换:
val msg1 = ProtocolCommands.ProtocolMsg("foo", 1)
val msg2 = Generic[RoutingCommands.ProtocolMsg].from(
Generic[ProtocolCommands.ProtocolMsg].to(msg1)
)
但是对于每次转换都必须这样做,而不仅仅是手动构建案例类。理想情况下,我想要一个转换器,它可以根据编译时提供的两种类型派生上述代码,例如val msg2 = convert(msg1)
作为迈出的一步,我试图将其分解为:
def convert[A,B](a: A): B = Generic[B].from(
Generic[A].to(a)
)
但这会导致:
Error:(55, 44) could not find implicit value for parameter gen: shapeless.Generic[B]
从四处挖掘,似乎我需要使用Generic.Aux
which 导致我:
def convert[A, B, HL <: HList](a: A)(
implicit
genA: Generic.Aux[A, HL],
genB: Generic.Aux[B, HL]
) = genB.from(genA.to(a))
其中,当调用:
val msg3 = convert(msg2)
结果是:
Error:(61, 57) could not find implicit value for parameter genB: shapeless.Generic.Aux[B,HL]
这是可以理解的,因为没有定义返回类型。但是,我想出了如何提供暗示什么B
是genB
可以隐式推导的。
解决方案
您可以使用“部分应用程序”
def convert[A, HL <: HList](a: A)(
implicit
genA: Generic.Aux[A, HL]
) = new Helper(a, genA)
class Helper[A, HL <: HList](a: A, genA: Generic.Aux[A, HL]) {
def apply[B](implicit genB: Generic.Aux[B, HL]) = genB.from(genA.to(a))
}
val msg3 = convert(msg2).apply[ProtocolCommands.ProtocolMsg]
(最好使用@Ben 回答中的“部分应用程序”)
或创建一个类型类
trait Convert[A, B] {
def apply(a: A): B
}
object Convert {
implicit def mkConvert[A, B, HL <: HList](implicit
genA: Generic.Aux[A, HL],
genB: Generic.Aux[B, HL]
): Convert[A, B] = a => genB.from(genA.to(a))
}
implicit class ConvertOps[A](a: A) {
def convert[B](implicit cnv: Convert[A, B]): B = cnv(a)
}
val msg3 = msg2.convert[ProtocolCommands.ProtocolMsg]
https://books.underscore.io/shapeless-guide/shapeless-guide.html#sec:ops:migration “6.3 案例研究:案例类迁移”
推荐阅读
- node.js - 如何从 Mongoose Graphql 的一对一关系的反向模型中获取数据?
- android - Android:在片段中定义的应用栏中覆盖向上导航
- html - 图像、字体、网站图标等仅出现在 Safari 中,但不在 Chrome 或移动设备中?
- visual-studio-code - VSCode:将光标移动到每个光标的给定单词的下一个出现
- php - 更新关系内的关系 hasMany 值
- django - 重写 Django 模型以删除不必要的主键后收到 InvalidCursorName 错误消息
- javascript - 填写所有字段时显示 div
- sql-server - 我有以下代码可以使用 Python 从 SQL Server 编写输出:输出为 '1'、'2'、'3',但我想要 1 2 3
- windows - 如果 Win 键是使用 AutoHotkey 按下的唯一键,如何禁用它?
- python - Python - discord.py,如何修复“事件循环已关闭”