编译器无法找到无形LabelledGeneric的正确隐式对象 [英] Compiler cannot find right implicits for shapeless LabelledGeneric

查看:90
本文介绍了编译器无法找到无形LabelledGeneric的正确隐式对象的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

继续讨论转换case classesMap[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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆