问题
I'd like to get the name of a type, as a String, without runtime reflection.
Using macros, and with an instance of the type, I can do it like this:
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)))
}
How can I do this without an instance of the type? I'd like a function signature like:
def typeName[A]: String
I can't use ClassTags because they don't provide the full type name, just the erased type. I also apparently can't use TypeTags because of thread safety issues.
EDIT: It appears this isn't possible in full generality (eg nested function calls). The accepted answer below states this in the comments.
回答1:
You can access tree that represents macro application: 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())
}
EDIT:
Another way to get the same, but maybe a little nicer:
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())
}
来源:https://stackoverflow.com/questions/15649720/scala-get-type-name-without-runtime-reflection-and-without-type-instance