You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为带类型参数的样例类推导Generic.Aux(Shapeless)

Scala泛型编程:为(A, Long)生成指定Coproduct的Generic实例

给定代码

sealed trait Data
final case class Foo() extends Data
final case class Bar() extends Data

final case class TimestampedData[A <: Data](data: A, timestamp: Long)

需求

是否能简洁生成Generic.Aux[(A, Long), TimestampedData[Foo] :+: TimestampedData[Bar] :+: CNil],让Generic将(A, Long)(A <: Data)映射为上述Coproduct类型?

解决方案

可以借助shapeless库的泛型能力实现,步骤如下:

1. 引入依赖

首先确保项目中添加shapeless依赖(以sbt为例):

libraryDependencies += "com.chuusai" %% "shapeless" % "2.3.10"

2. 实现自定义Generic实例

利用shapeless自动为sealed trait生成的Coproduct表示,结合类型转换完成实例定义:

import shapeless._

// 自动获取Data的Coproduct类型表示
type DataCoproduct = Generic[Data]#Repr // 等价于 Foo :+: Bar :+: CNil
// 将DataCoproduct中的每个类型包装为TimestampedData
type TimestampedDataCoproduct = DataCoproduct#Aux[TimestampedData]

// 为(A, Long)实现Generic实例
implicit def timestampedDataGeneric[A <: Data]: Generic.Aux[(A, Long), TimestampedDataCoproduct] = 
  new Generic[(A, Long)] {
    override type Repr = TimestampedDataCoproduct

    override def to(tuple: (A, Long)): Repr = {
      val (data, ts) = tuple
      // 先将Data转为对应Coproduct元素,再包装为TimestampedData
      Generic[Data].to(data).map(TimestampedData(_, ts))
    }

    override def from(coproduct: Repr): (A, Long) = {
      // 从Coproduct中提取TimestampedData,拆解为元组
      coproduct.eliminate(
        tsFoo => (tsFoo.data, tsFoo.timestamp),
        remaining => remaining.eliminate(
          tsBar => (tsBar.data, tsBar.timestamp),
          _ => throw new IllegalArgumentException("无效的Coproduct元素")
        )
      )
    }
  }

说明

  • shapeless会自动为sealed trait Data生成Generic[Data]实例,其Repr就是Foo :+: Bar :+: CNil。
  • 通过DataCoproduct#Aux[TimestampedData]可以将Coproduct中的每个类型X转换为TimestampedData[X],得到目标Coproduct类型。
  • 自定义的Generic实例中,to方法负责将(A, Long)转换为目标Coproduct,from方法则完成反向转换。

内容的提问来源于stack exchange,提问作者eitaporra

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 12:25:59