LabelledGeneric 获取类名 [英] LabelledGeneric to get class name

查看:63
本文介绍了LabelledGeneric 获取类名的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm fairly new to Shapeless, as one will infer from my question. Given an instance of LabelledGeneric, how do I get the name of the class that it represents. I can get the field name information from Keys, so I assume I need some other kind of Witness that encapsulates the type itself, but I cannot figure out which.

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

Eg, if I have a case class called Foo in package com.bar, I want to get the string "com.bar.Foo" (or separately is fine).

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 = ???
}

推荐答案

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

Shapeless's Generic provides a sum-of-products representation for case classes and sealed traits, which means that if we have a simple ADT like this:

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

然后 Generic[Base] 会给我们一个到 Foo.type :+: Bar :+: CNil 的映射——即a Foo.type or a Bar(其中 or 表示我们正在谈论和类型"在类型理论术语中),并且 Generic[Bar] 为我们提供了到 Int :: String :: HNil 的映射,即 Int一个 String(一种产品类型,其中product"的含义与 scala.ProductN 类型的情况大致相同在标准库中).

Then Generic[Base] will give us a mapping to a Foo.type :+: Bar :+: CNil—i.e. a Foo.type or a Bar (where the or means we're talking about a "sum type" in type theoretic terms), and a Generic[Bar] gives us a mapping to an Int :: String :: HNil, which is Int and a String (a product type, where "product" has roughly the same meaning that it does in the case of the scala.ProductN types in the standard library).

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

LabelledGeneric uses an enhanced version of the sum-of-products representation, where each of the terms in the product or sum is tagged with a label. In the case of a sealed trait, these will be the constructor names for each subtype, and in the case of a case class they'll be the member names. These aren't fully-qualified names—just labels that disambiguate locally.

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

Generic and LabelledGeneric aren't intended to serve as general-purpose tools for compile-time reflection. They're not available for arbitrary types, for example, and they don't provide access to the name of the type itself.

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

Your best bet is probably to use TypeTag, but if you want a type-level representation of the name (like LabelledGeneric provides for labels), you'll need to define your own type class with macro-generated instances. Something like the following should work:

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 }"
  }
}

不过,如果您只需要值级字符串,这对于您的用例来说可能有点矫枉过正.

This is probably overkill for your use case, though, if you only need value-level strings.

这篇关于LabelledGeneric 获取类名的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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