2015-04-20 50 views
2

我有一個對嵌套函數應用程序進行一些分析的宏。它匹配的應用和檢索的參數類型是這樣的:在Scala宏中處理by-name參數

case q"$f[..$targs](..$args)(...$otherArgs)" => 

    // retrieve the list of all parameter types 
    val paramTpes = f.tpe match { 
     case pmt: PolyType if pmt.paramLists.size == 0 => 
     Seq() 
     case pmt: PolyType => 
     pmt.paramLists(0) map {_.typeSignature 
      .substituteTypes(pmt.typeParams, targs map (_.tpe))} 
     case pmt: MethodType if pmt.paramLists.size == 0 => 
     Seq() 
     case pmt: MethodType => 
     pmt.paramLists(0) map (_.typeSignature) 
    } 

現在,如果碰巧是按名稱參數,我得到的是一些奇怪的類型,打印=> T,但不能與任何匹配。在反射API中似乎沒有任何工具可以正確處理這些問題。 我想要做的是檢索T的情況下,'=> T,因爲=> T導致進一步生成的代碼中的問題。

回答

4

通常,使用提取器。有時我必須查看運行時類是什麼,才能記住要使用的提取器。我不會每天都使用這個API。

scala> import reflect.runtime._, universe._ 
import reflect.runtime._ 
import universe._ 

scala> class X { def x(i: => Int) = i * 2 } 
defined class X 

scala> typeOf[X].member(TermName("x")) 
res0: reflect.runtime.universe.Symbol = method x 

scala> .typeSignature 
res1: reflect.runtime.universe.Type = (i: => scala.Int)scala.Int 

scala> res1 match { case MethodType(ps, res) => ps } 
res2: List[reflect.runtime.universe.Symbol] = List(value i) 

scala> .head 
res3: reflect.runtime.universe.Symbol = value i 

scala> .typeSignature 
res4: reflect.runtime.universe.Type = => scala.Int 

scala> res4.getClass 
res5: Class[_ <: reflect.runtime.universe.Type] = class scala.reflect.internal.Types$ClassArgsTypeRef 

scala> res4 match { case TypeRef(pre, sym, args) => sym } 
res6: reflect.runtime.universe.Symbol = class <byname> 

scala> res4 match { case TypeRef(pre, sym, args) => args } 
res7: List[reflect.runtime.universe.Type] = List(scala.Int) 

scala> definitions 
res8: reflect.runtime.universe.DefinitionsApi = [email protected] 

scala> definitions.By 
ByNameParamClass ByteClass ByteTpe 

scala> definitions.ByNameParamClass 
res9: reflect.runtime.universe.ClassSymbol = class <byname> 

我依稀記得特殊的名字,但是我得到一個穩定的模式匹配前綴嗎?我猜不會。

scala> res4 match { case TypeRef(pre, definitions.ByNameParamClass, args) => args } 
<console>:20: error: stable identifier required, but scala.reflect.runtime.`package`.universe.definitions.ByNameParamClass found. 
Note that method ByNameParamClass is not stable because its type, => reflect.runtime.universe.ClassSymbol, is volatile. 
       res4 match { case TypeRef(pre, definitions.ByNameParamClass, args) => args } 
                 ^

scala> val k = definitions.ByNameParamClass 
k: reflect.runtime.universe.ClassSymbol = class <byname> 

scala> res4 match { case TypeRef(pre, k, args) => args } 
res11: List[reflect.runtime.universe.Type] = List(scala.Int) 

scala> 
+0

謝謝,它使用'c.universe.definitions.ByNameParamClass'。我接近找到解決方案,通過修復repl,但不是那裏! –