如何对比不同泛型HList的类型以实现序列化器静态类型校验?
问题核心原因
你编写的泛型方法toSerializedKeys没有声明需要的隐式证据,编译器无法为任意的ReprA和ReprB类型自动推导匹配的Serializer实例,因此会报找不到实例的错误。
修复方案
1. 基础修复(直接传入HList场景)
给toSerializedKeys方法补充对应的隐式参数即可:
def toSerializedKeys[ReprA <: HList, ReprB <: HList]( keys: ReprA, fns: ReprB )(implicit serializer: Serializer[ReprA, ReprB]): List[ByteBuffer] = Serializer.toBufs(keys)(fns)
调整后原来的测试用例可以正常编译,类型不匹配的场景依然会在编译期抛出错误,符合你的需求。
2. 支持用户传入样例类+元组描述符的原生用法
如果要支持你最开始举例的用户使用方式(不需要用户手动把样例类、元组转为HList),需要额外引入shapeless的Generic隐式转换,把用户传入的Product类型自动转为对应结构的HList:
import shapeless.Generic def toSerializedKeys[K <: Product, D <: Product, ReprK <: HList, ReprD <: HList]( keys: K, keyDescriptor: D )(implicit genK: Generic.Aux[K, ReprK], // 把keys样例类转为对应结构的HList genD: Generic.Aux[D, ReprD], // 把描述符元组转为对应结构的HList serializer: Serializer[ReprK, ReprD] ): List[ByteBuffer] = Serializer.toBufs(genK.to(keys))(genD.to(keyDescriptor))
调整后你最开始的示例可以直接正常使用:
case class Keys(key1: String, key2: Int) val keys = Keys("Foo", 2) val keyDescriptor = (StringSerializerFn, IntSerializerFn) // 正常编译 toSerializedKeys(keys, keyDescriptor) val badDescriptor = (StringSerializerFn, StringSerializerFn) // 编译期报错:序列化器类型不匹配 toSerializedKeys(keys, badDescriptor)
3. 可选方案:使用全局隐式序列化器
如果你不想让用户每次传入和键结构匹配的描述符元组,也可以实现基于隐式作用域的序列化方案,代码更简洁:
首先定义单HList的序列化类型类:
trait ImplicitSerializer[L <: HList] { def toBufs(keys: L): List[ByteBuffer] } object ImplicitSerializer { implicit val hnilInst: ImplicitSerializer[HNil] = _ => Nil implicit def hconsInst[H, T <: HList](implicit ser: SerializerFn[H], tailInst: ImplicitSerializer[T] ): ImplicitSerializer[H :: T] = keys => ser.toBytes(keys.head) :: tailInst.toBufs(keys.tail) // 对外暴露的样例类适配方法 def serialize[K <: Product, Repr <: HList](keys: K)(implicit gen: Generic.Aux[K, Repr], ser: ImplicitSerializer[Repr] ): List[ByteBuffer] = ser.toBufs(gen.to(keys)) }
用户只需要在作用域内声明对应类型的隐式序列化器即可直接调用:
implicit val strSer = StringSerializerFn implicit val intSer = IntSerializerFn val keys = Keys("Foo", 2) // 直接调用即可,不需要传描述符 ImplicitSerializer.serialize(keys)
内容的提问来源于stack exchange,提问作者jrock7
相关产品推荐
相关产品推荐

