【问题标题】:Get case class field's name and type with shapeless使用无形获取案例类字段的名称和类型
【发布时间】:2019-04-05 12:35:49
【问题描述】:

是否可以使用无形获取 scala 案例类字段的名称和类型?

我试过这样(T是案例类):

trait Cpo[T] {

def withPrimaryKey[R <: HList, K, V <: HList](f: Seq[Symbol] => Seq[Symbol])(
    implicit labellGeneric: LabelledGeneric.Aux[T, R], keys: Keys.Aux[R, K],
    ktl: hlist.ToList[K, Symbol]): Cpo[T]
}

但我只能获取字段的名称。

兹拉亚

【问题讨论】:

  • 有必要使用 shapeless 吗?询问是因为您可以使用 Product 类轻松做到这一点
  • @Shantiswarup,有什么例子吗?
  • 我已添加示例代码作为此问题的答案

标签: scala shapeless


【解决方案1】:

试试

object typeablePoly extends Poly1 {
  implicit def default[A](implicit typeable: Typeable[A]): Case.Aux[A, String] = at(_ => typeable.describe)
}

trait Cpo[T] {

  def withPrimaryKey[R <: HList, K <: HList, V <: HList, V1 <: HList](f: Seq[Symbol] => Seq[Symbol])(implicit
    labellGeneric: LabelledGeneric.Aux[T, R],
    keys: Keys.Aux[R, K],
    ktl: hlist.ToList[K, Symbol],
    values: Values.Aux[R, V],
    mapper: hlist.Mapper.Aux[typeablePoly.type, V, V1],
    vtl: hlist.ToList[V1, String]
  ): Cpo[T] 
}

现在ktl 给出字段名称列表(如Symbols),vtl 给出字段类型列表(如Strings)。


试试

  object typeablePoly extends Poly1 {
    implicit def default[A](implicit typeable: Typeable[A]): Case.Aux[A, String] = at(_ => typeable.describe)
  }

  object nullPoly extends Poly0 {
    implicit def default[A]: ProductCase.Aux[HNil, A] = at(null.asInstanceOf[A])
  }

  trait Cpo[T] {

    def withPrimaryKey[R <: HList, K <: HList, V <: HList, V1 <: HList](f: Seq[Symbol] => Seq[Symbol])(implicit
      labellGeneric: LabelledGeneric.Aux[T, R],
      keys: Keys.Aux[R, K],
      ktl: hlist.ToList[K, Symbol],
      values: Values.Aux[R, V],
      mapper: hlist.Mapper.Aux[typeablePoly.type, V, V1],
      fillWith: hlist.FillWith[nullPoly.type, V],
      vtl: hlist.ToList[V1, String]
    ): Cpo[T] = {
      println(ktl(keys())) // List('i, 's)
      println(vtl(mapper(fillWith()))) // List(Int, String)
      ???
    }
  }

  case class MyClass(i: Int, s: String)
  new Cpo[MyClass] {}.withPrimaryKey(identity)

【讨论】:

  • 如果我计算正确,要获得字段类型,我需要有 T 的实例?是否可以仅使用类型 T 获取字段类型?
【解决方案2】:

您绝对可以获得字段名称。例如,您可以在这里找到如何编写基于无形的泛型派生机制:Bits of shapeless part 2。 更具体地说,你应该看Deriving case Classes部分,有一个函数可以为任意case类派生编码器,它的签名是:

implicit def hconsToJson[Key <: Symbol, Head, Tail <: HList](
    implicit key: Witness.Aux[Key],
    headWrites: JsonWrites[Head],
    tailWrites: JsonWrites[Tail])
    : JsonWrites[FieldType[Key, Head] :: Tail] = ???

因此,key 参数允许您访问特定字段的字段名称。 对于这些类型,我唯一知道的方法是使用反射。阅读本文了解详情Scala manual on type tags

【讨论】:

    【解决方案3】:

    如果不需要使用 shapeless,您可以使用 scala 中的 Product 类获取类型和值

    case class Test(x:Int,y:String,z:Boolean)
    println(getGeyNameValueType(Test(1,"a",true)).foreach(println))
    
    def getGeyNameValueType(inp: Product): Iterator[(Any, Class[_])] = {
        val itr = inp.productIterator
        for {
          item <- itr
        } yield (item, item.getClass)
    }
    

    输出是

    (1,class java.lang.Integer)
    (a,class java.lang.String)
    (true,class java.lang.Boolean)
    ()
    

    【讨论】:

    • 是的,但它必须有 T 的实例。我想在没有实例的情况下这样做。我用无形做的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-12-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-11-27
    • 2015-06-27
    • 1970-01-01
    相关资源
    最近更新 更多