如何使用Circe对Map[K,V]类型数据进行编码
要实现Map[K, V]的Circe编解码,你需要为自定义键类型K分别实现KeyEncoder和KeyDecoder,值类型V直接用Circe的常规编解码派生即可。
完整实现示例
1. 基础依赖(sbt)
libraryDependencies ++= Seq( "io.circe" %% "circe-core" % "0.14.6", "io.circe" %% "circe-generic" % "0.14.6", "io.circe" %% "circe-parser" % "0.14.6" )
2. 业务代码实现
import io.circe._ import io.circe.generic.semiauto._ import io.circe.syntax._ // 你定义的样例类 case class K(a1: String, a2: String) case class V(b1: String, b2: String) object K { // 方案1:用分隔符拼接K的字段作为键,性能更高,适合字段无特殊分隔符的场景,此处用|作为分隔符可自行替换 implicit val kKeyEncoder: KeyEncoder[K] = (key: K) => s"${key.a1}|${key.a2}" implicit val kKeyDecoder: KeyDecoder[K] = (keyStr: String) => { keyStr.split('|') match { case Array(a1, a2) => Some(K(a1, a2)) case _ => None } } /* 方案2:把K序列化为JSON字符串作为键,适合字段可能含任意字符的场景,取消注释即可使用 implicit val kEncoder: Encoder[K] = deriveEncoder[K] implicit val kDecoder: Decoder[K] = deriveDecoder[K] implicit val kKeyEncoder: KeyEncoder[K] = (key: K) => key.asJson.noSpaces implicit val kKeyDecoder: KeyDecoder[K] = (keyStr: String) => io.circe.parser.parse(keyStr).flatMap(_.as[K]).toOption */ } object V { // V是普通值类型,直接派生编解码器即可 implicit val vEncoder: Encoder[V] = deriveEncoder[V] implicit val vDecoder: Decoder[V] = deriveDecoder[V] } // 测试用例 object CirceMapTest extends App { val testMap = Map( K("key1_part1", "key1_part2") -> V("val1_part1", "val1_part2"), K("key2_part1", "key2_part2") -> V("val2_part1", "val2_part2") ) // 编码为JSON val json = testMap.asJson println(json.noSpaces) // 方案1输出示例:{"key1_part1|key1_part2":{"b1":"val1_part1","b2":"val1_part2"},"key2_part1|key2_part2":{"b1":"val2_part1","b2":"val2_part2"}} // 反序列化回Map[K,V] val decoded = json.as[Map[K, V]] println(decoded) // 输出:Right(Map(K(key1_part1,key1_part2) -> V(val1_part1,val1_part2), K(key2_part1,key2_part2) -> V(val2_part1,val2_part2))) }
注意事项
- 两种键序列化方案可以根据业务场景选择,核心要求是保证一个
K实例对应唯一的字符串,且字符串可以反向解析回K实例 - 如果不需要反序列化功能,可以只实现
KeyEncoder即可
内容的提问来源于stack exchange,提问作者martav
相关产品推荐
相关产品推荐

