2013-03-27 65 views
0

我想以一個字符串的形式獲取類型的名稱,沒有運行時反射。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,因爲它們不提供完整的類型名稱,只是擦除類型。由於thread safety issues,我顯然也不能使用TypeTags。

編輯:這似乎是不可能的完全一般性(例如嵌套函數調用)。下面接受的答案在評論中說明了這一點。

回答

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

該解決方案不會返回最終的靜態類型。假設我定義了:「def printType [A] = println(typeName [A])」。然後調用「printType [List [Int]]」打印「A」而不是「List [Int]」。 – emchristiansen 2013-03-27 18:23:15

+0

如果你希望它能像這樣工作,那麼我認爲沒有'TypeTag's是不可能的。宏在編譯過程中被擴展,所以你的代碼: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 2013-03-27 18:59:53

相關問題