编译器无法找到无形LabelledGeneric的正确隐式对象 [英] Compiler cannot find right implicits for shapeless LabelledGeneric
问题描述
继续讨论转换case classes
和Map[String,Any]
的问题,当我想以通用方式使用它时遇到了一些问题,
Continuing the discussion about converting case classes
and Map[String,Any]
, I faced some problems when I wanted to use it in a generic way, Here is the main discussion.
当我想使用如下通用方法时,编译器会抱怨隐式:
And when I want to use a generic method like following, compiler complains about the implicits:
import MapConvertor._
def convert[A](cc: A)= {
cc.toMapRec
}
以下是提供toMapRec
的全部代码:
Here is the whole code that provides toMapRec
:
import shapeless._, labelled.FieldType, record._
trait ToMapRec[L <: HList] { def apply(l: L): Map[String, Any] }
trait LowPriorityToMapRec {
implicit def hconsToMapRec1[K <: Symbol, V, T <: HList](implicit
wit: Witness.Aux[K],
tmrT: ToMapRec[T]
): ToMapRec[FieldType[K, V] :: T] =
new ToMapRec[FieldType[K, V] :: T] {
def apply(l: FieldType[K, V] :: T): Map[String, Any] =
tmrT(l.tail) + (wit.value.name -> l.head)
}
}
object ToMapRec extends LowPriorityToMapRec {
implicit val hnilToMapRec: ToMapRec[HNil] = new ToMapRec[HNil] {
def apply(l: HNil): Map[String, Any] = Map.empty
}
implicit def hconsToMapRec0[K <: Symbol, V, R <: HList, T <: HList](implicit
wit: Witness.Aux[K],
gen: LabelledGeneric.Aux[V, R],
tmrH: ToMapRec[R],
tmrT: ToMapRec[T]
): ToMapRec[FieldType[K, V] :: T] = new ToMapRec[FieldType[K, V] :: T] {
def apply(l: FieldType[K, V] :: T): Map[String, Any] =
tmrT(l.tail) + (wit.value.name -> tmrH(gen.to(l.head)))
}
}
object MapConvertor {
implicit class ToMapRecOps[A](val a: A) extends AnyVal {
def toMapRec[L <: HList](implicit
gen: LabelledGeneric.Aux[A, L],
tmr: ToMapRec[L]
): Map[String, Any] = tmr(gen.to(a))
}
}
推荐答案
您需要证明代表A
的记录具有ToMapRec
实例,您可以这样操作:
You'll need to prove that the record that represents A
has a ToMapRec
instance, which you can do like this:
def convert[A, R <: HList](cc: A)(implicit
gen: LabelledGeneric.Aux[A, R],
tmr: ToMapRec[R]
) = tmr(gen.to(cc))
您还可以引入一个新的类型类来对此进行清理:
You can also introduce a new type class to clean this up a bit:
trait CcToMapRec[A] { def apply(a: A): Map[String, Any] }
object CcToMapRec {
implicit def ccToMapRec[A, R <: HList](implicit
gen: LabelledGeneric.Aux[A, R],
tmr: ToMapRec[R]
): CcToMapRec[A] = new CcToMapRec[A] {
def apply(a: A): Map[String, Any] = tmr(gen.to(a))
}
}
然后您的方法只需要一个隐式参数:
And then your method just needs a single implicit parameter:
def convert[A](cc: A)(implicit ctmr: CcToMapRec[A]) = ctmr(cc)
但是您仍然需要通过具有要转换的泛型类型的任何方法将此实例线程化.
But you'll still need to thread this instance through any method with a generic type that you intend to convert.
这篇关于编译器无法找到无形LabelledGeneric的正确隐式对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!