LabelledGenerid.Aux 在函数体中使用通用类型时隐式不可用

LabelledGenerid.Aux implicit not available when using generic type in function body

我正在尝试这个并且有效:

`
    case class Foo(name: String)

class Morphic(map: Map[String, Any]) { def add(k: String, v: Any) = { new Morphic((map + (k -> v))) } def to[T](): T = { def toClass[A]: ToCase[A] = new ToCase[A] // This is class to convert from Map to case class val res = toClass[Foo].from(map).get // <-- problem is here - cannot use T res.asInstanceOf[T] } } object testApp extends App { var m = new Morphic(Map[String, Any]()) var m1 = m.add("name", "john") println(m1.to[Foo]) }

我应该在 val res = toClass[T].from(map).get 中使用 T 而不是 Foo,但它没有编译说缺少隐式

toClass[T].from 是一个从 Map

创建给定类型案例 class 的函数

如何使隐式(以及 .from 所依赖的其他隐式)可用?

我试过 def to[T, H <: HList]()(implicit gen: LabelledGeneric.Aux[A, H]) = ... 但是我需要在调用 .to 时指定这两种类型,我不知道要为 H

指定什么

谢谢

您可以将Map转换为HList,然后将HList转换为T

import shapeless.{::, HList, HNil, LabelledGeneric, Witness}
import shapeless.labelled._

case class Foo(name: String)

trait MapToHList[L <: HList] {
  def apply(map: Map[String, Any]): Option[L]
}
object MapToHList {
  implicit object hNilMapToHList extends MapToHList[HNil] {
    override def apply(map: Map[String, Any]): Option[HNil] = Some(HNil)
  }

  implicit def hConsMapToHList[K <: Symbol, V, T <: HList](implicit
                                                           mapToHList: MapToHList[T],
                                                           witness: Witness.Aux[K]
                                                          ): MapToHList[FieldType[K, V] :: T] =
    new MapToHList[FieldType[K, V] :: T] {
      override def apply(map: Map[String, Any]): Option[FieldType[K, V] :: T] = {
        val str = witness.value.toString.tail
        for {
          v <- map.get(str)
          t <- mapToHList(map)
        } yield field[K](v.asInstanceOf[V]) :: t
      }
    }
}

trait ToCase[A] {
  def from(map: Map[String, Any]): Option[A]
}
object ToCase {
  implicit def mkToCase[A, L <: HList](implicit
                                       gen: LabelledGeneric.Aux[A, L],
                                       mapToHList: MapToHList[L]
                                      ): ToCase[A] =
    new ToCase[A] {
      override def from(map: Map[String, Any]): Option[A] = mapToHList(map).map(gen.from)
    }
}


class Morphic(map: Map[String, Any]) {

  def add(k: String, v: Any) = {
    new Morphic((map + (k -> v)))
  }

  def to[T](implicit toCase: ToCase[T]): T = toCase.from(map).get

}

object testApp extends App {
  var m = new Morphic(Map[String, Any]())
  var m1 = m.add("name", "john")
  println(m1.to[Foo]) // Foo(john)
}

I tried def to[T, H <: HList]()(implicit gen: LabelledGeneric.Aux[A, H]) ... but then I need to specify both types when calling the .to and I can't figure out what to specify for H

您可以将其命名为 m1.to[Foo, FieldType[Witness.`'name`.T, String] :: HNil]()m1.to[Foo, Record.`'name -> String`.T]()