【问题标题】:LabelledGeneric to get class nameLabelledGeneric 获取类名
【发布时间】:2017-08-22 16:11:33
【问题描述】:

我对 Shapeless 还很陌生,从我的问题中可以推断出来。给定LabelledGeneric 的实例,我如何获取它所代表的类的名称。我可以从Keys 获取字段名称信息,所以我假设我需要一些其他类型的Witness 来封装类型本身,但我不知道是哪个。

例如,如果我在 com.bar 包中有一个名为 Foo 的案例类,我想获取字符串“com.bar.Foo”(或者单独获取也可以)。

implicit def example[T, Repr <: HList](implicit label: LabelledGeneric.Aux[T, Repr],
                                         kk: Keys[Repr]): Bibble[T] = new Bibble[T] {
  override def typeName(value: T): String = ???
}

【问题讨论】:

  • 也许你可以使用 scala reflect `scala.reflect.runtime.universe.typeOf[Foo].typeSymbol.fullName`
  • 我可以使用 manifests 或 typetags,但我想我宁愿在 shapeless 中这样做,因为我同时将 shapeless 用于其他事情。
  • classOf[String].getSimpleName,它不是无形的

标签: scala shapeless


【解决方案1】:

Shapeless 的 Generic 为案例类和密封特征提供了积和表示,这意味着如果我们有一个像这样的简单 ADT:

sealed trait Base
case object Foo extends Base
case class Bar(i: Int, s: String) extends Base

然后Generic[Base] 会给我们一个到Foo.type :+: Bar :+: CNil 的映射——即Foo.type or Bar (其中 or 表示我们在类型理论术语中讨论的是“总和类型”),Generic[Bar] 给出我们映射到Int :: String :: HNil,即Int String(一种产品类型,其中“产品”的含义与@987654331 的含义大致相同@ 标准库中的类型)。

LabelledGeneric 使用积和表示的增强版本,其中积或总和中的每个术语都带有标签。在密封特征的情况下,这些将是每个子类型的构造函数名称,而在案例类的情况下,它们将是成员名称。这些不是完全限定的名称——只是在本地消除歧义的标签。

GenericLabelledGeneric 并非旨在用作编译时反射的通用工具。例如,它们不适用于任意类型,并且它们不提供对类型本身名称的访问。

您最好的选择可能是使用TypeTag,但如果您想要名称的类型级别表示(如LabelledGeneric 提供标签),您需要使用宏生成定义自己的类型类实例。像下面这样的东西应该可以工作:

import scala.language.experimental.macros
import scala.reflect.macros.whitebox.Context

trait TypeInfo[A] { type Name <: String; def name: String }

object TypeInfo {
  type Aux[A, Name0 <: String] = TypeInfo[A] { type Name = Name0 }

  def apply[A](implicit ti: TypeInfo[A]): Aux[A, ti.Name] = ti

  implicit def materializeTypeInfo[A, Name <: String]: Aux[A, Name] =
    macro matTypeInfoImpl[A, Name]

  def matTypeInfoImpl[A: c.WeakTypeTag, Name <: String](c: Context): c.Tree = {
    import c.universe._

    val A = c.weakTypeOf[A]
    val name = A.typeSymbol.name.decodedName.toString.trim

    q"new TypeInfo[$A] { type Name = ${ Constant(name) }; def name = $name }"
  }
}

不过,如果您只需要值级别的字符串,这对于您的用例来说可能是多余的。

【讨论】:

  • 我现在正在使用宏来生成我想要的数据,但它开始变得有点笨拙,而且无形对于操作案例类的字段非常方便。所以我想我的问题的答案是我不能使用 shapeless 作为类型名称。我可能会尝试结合类型标签和无形然后。
猜你喜欢
  • 1970-01-01
  • 2021-01-14
  • 2019-05-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-09-20
  • 2011-02-04
相关资源
最近更新 更多