【问题标题】:Scala: Get type name without runtime reflection and without type instanceScala:在没有运行时反射和没有类型实例的情况下获取类型名称
【发布时间】:2013-03-27 00:05:03
【问题描述】:

我想获得一个类型的名称,作为一个字符串,没有运行时反射。

使用宏和类型的实例,我可以这样做:

def typeNameFromInstance[A](instance: A): String = 
  macro typeNameFromInstanceImplementation[A]

def typeNameFromInstanceImplementation[A](
  c: Context)(
    instance: c.Expr[A]): c.Expr[String] = {
  import c.universe._

  val name = instance.actualType.toString
  c.Expr[String](Literal(Constant(name)))
}

如果没有该类型的实例,我该如何做到这一点?我想要一个函数签名,例如:

def typeName[A]: String

我不能使用 ClassTag,因为它们不提供完整的类型名称,只提供已擦除的类型。由于thread safety issues,我显然也不能使用TypeTags。

编辑:看起来这是不可能的(例如嵌套函数调用)。下面接受的答案在 cmets 中说明了这一点。

【问题讨论】:

    标签: scala macros metaprogramming


    【解决方案1】:

    您可以访问代表宏应用程序的树:c.macroApplication

    def typeName[T]: String = macro typeName_impl[T]
    
    def typeName_impl[T](c: Context): c.Expr[String] = {
      import c.universe._
    
      val TypeApply(_, List(typeTree)) = c.macroApplication
      c.literal(typeTree.toString())
    }
    

    编辑:

    获得相同效果的另一种方法,但可能更好一点:

    def typeName[T]: String = macro typeName_impl[T]
    
    def typeName_impl[T: c.WeakTypeTag](c: Context): c.Expr[String] = {
      import c.universe._
    
      c.literal(weakTypeOf[T].toString())
    }
    

    【讨论】:

    • 此解决方案不返回最终的静态类型。假设我定义:“def printType[A] = println(typeName[A])”。然后调用“printType[List[Int]]”打印“A”而不是“List[Int]”。
    • 如果你想让它像这样工作,那么我认为没有TypeTags 是不可能的。宏在编译期间被扩展,所以你的代码:def printType[A] = println(typeName[A]) 实际上被翻译成def printType[A] = println("A")。您在这里唯一可以做的就是将printType 也定义为一个宏。它的实现可能如下所示:def printType_impl[T](c: Context): c.Expr[Unit] = c.universe.reify(println(typeName_impl[T](c).splice))
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-09-20
    • 1970-01-01
    • 2018-04-02
    • 2020-10-14
    • 2011-02-11
    • 1970-01-01
    相关资源
    最近更新 更多