如何在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
相关产品推荐
相关产品推荐

