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

如何在Shapeless的HMap上实现类似HList的collect、fold等操作?

Shapeless 没有为 HMap 直接提供类似 HListOps 的内置高阶操作接口,但可以通过 HMap 原生支持的转 HList 能力,间接复用 HList 的所有原生操作满足你的需求,全程无需自定义核心逻辑。

Shapeless 的 HMap 本质是对异构键值对 HList 的封装,所有键值对都以 Tuple 形式存储在底层 HList 中,你可以直接通过 .toHList 方法拿到对应的异构列表,之后即可直接调用原生的 collect、fold、filter 等方法。

完整使用示例如下:

import shapeless.{HMap, HList, Poly1, Poly2}
import java.time.Instant

// 你原有HMap的类型约束定义
class HOptionsMap[K, V]
implicit val strToString = new HOptionsMap[String, String]
implicit val strToInstant = new HOptionsMap[String, Instant]

// 构造HMap实例
val hm = HMap[HOptionsMap]("placeOfIncident" -> "Toronto", "incidentDate" -> Instant.now)

操作示例

// 先将HMap转为原生HList,类型为 (String, String) :: (String, Instant) :: HNil
val hlist = hm.toHList

// 1. foldLeft 操作:计算所有配置值的字符串总长度
object countLenFunc extends Poly2 {
  implicit val strCase: Case.Aux[Int, (String, String), Int] = 
    at((acc, kv) => acc + kv._2.length)
  implicit val instantCase: Case.Aux[Int, (String, Instant), Int] = 
    at((acc, kv) => acc + kv._2.toString.length)
}
val totalLength = hlist.foldLeft(0)(countLenFunc)

// 2. filter 操作:过滤出值类型为String的配置项
object isStringKV extends Poly1 {
  implicit val strCase: Case.Aux[(String, String), Boolean] = at(_ => true)
  implicit val instantCase: Case.Aux[(String, Instant), Boolean] = at(_ => false)
}
val stringConfigItems = hlist.filter(isStringKV)

// 3. collect 操作:提取所有值为Instant类型的时间戳
object collectInstant extends Poly1 {
  implicit val instantCase: Case.Aux[(String, Instant), Instant] = at(_._2)
}
val timeStamps = hlist.collect(collectInstant)

如果操作后的 HList 所有键值对仍然满足你定义的 HOptionsMap 隐式约束,可直接重新构造为 HMap:

val newHm = HMap[HOptionsMap](stringConfigItems)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.30 13:06:06