2014-03-04 39 views
4

我需要將字符串值轉換爲實際類型,所以我決定嘗試使用宏方法來實現此目的。我有一大堆的數據類型:與宏中的子類匹配

sealed abstract class Tag(val name: String) 
case object Case1 extends Tag("case1") 
case object Case2 extends Tag("case2") 
case object Case3 extends Tag("case3") 
etc... 

我想寫一個簡單的域名解析:

val tag: Tag = TagResolver.fromString("case2") 

此行應分別返回Case2。我經理做到以下幾點:

def typeFromString(c: Context)(name: c.Expr[String]): c.Expr[Tag] = { 
    import c.universe._ 
    val tag = typeTag[Tag] 
    val accSymb = tag.tpe.typeSymbol.asClass 
    val subclasses = accSymb.knownDirectSubclasses // all my cases 

    subclasses.map { sub => 
     val name = sub.typeSignature.member(newTermName("name")).asMethod // name field 
     ??? 
    } 
    } 

但我怎麼能比得上name: c.Expr[String]name場的值,如果匹配返回相應的標籤?

回答

1

我不認爲有這樣做的可靠方式,因爲knownDirectSubclasses可以引用尚未編譯的類,所以我們無法評估它們。

如果您可以將這些值作爲註釋標記在類上,那麼即使在當前編譯運行中(通過Symbol.annotations API)編譯類時,也可以讀取這些註釋。但請注意,已知的DirectSubclasses有已知問題:https://issues.scala-lang.org/browse/SI-7046

+0

實際上,可以通過將字符串顯式映射到大小寫對象來模擬所需的行爲,反之亦然(例如,像Slick中的映射器那樣)。不是一個非常優雅的解決方案,但它適用於日常用途: - } – Ashalynd

+0

地圖可以由宏生成,它只是應該有一種方法來獲得這些名稱:或者通過像'@name(「case1」 )case對象Case1'或者通過一個可以在運行時解除引用的着名字段名稱(例如,一個宏可以生成'Map(Case1 - > Case1.name,...)')。 –