2013-03-27 2 views
0

Я хотел бы получить имя типа, как String, без отражения во время выполнения.Scala: Получить имя типа без отражения во время выполнения и без экземпляра типа

Использование макросов и с экземпляром типа, я могу сделать это так:

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 

Я не могу использовать ClassTags, потому что они не обеспечивают полное имя типа, просто стертый тип. Я также, видимо, не могу использовать TypeTags из-за thread safety issues.

EDIT: Похоже, что это невозможно в полной общности (например, вложенные вызовы функций). В принятом ответе ниже говорится об этом в комментариях.

ответ

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()) 
} 

EDIT:

Другой способ получить то же самое, но, возможно, немного лучше:

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()) 
} 
+0

Это решение не возвращает конечный статический тип. Предположим, что я определяю: «def printType [A] = println (typeName [A])». Затем вызов «printType [List [Int]]» печатает «A» не «Список [Int]». – emchristiansen

+0

Если вы хотите, чтобы это работало так, я не думаю, что это возможно без 'TypeTag'. Макрос расширяется во время компиляции, поэтому ваш код: '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))' – ghik

Смежные вопросы