2013-06-30 6 views
6

次は明白可変引数関数である。我々は、同様の方法でマクロを定義することができます可変パラメータでマクロを定義し、各パラメータの型を取得できますか?

def fun(xs: Any*) = ??? 

def funImpl(c: Context)(xs: c.Expr[Any]*) = ??? 

fun(1,"1",1.0) 

しかし、この場合には、すべての引数がAnyとして型指定されています。実際、コンパイラはコンパイル時に型を知っていますが、それを私たちから隠します。引数のリストをマクロ内での型にすることは可能ですか?

答えて

6

確か - 例えば:

import scala.language.experimental.macros 
import scala.reflect.macros.Context 

object Demo { 
    def at(xs: Any*)(i: Int) = macro at_impl 
    def at_impl(c: Context)(xs: c.Expr[Any]*)(i: c.Expr[Int]) = { 
    import c.universe._ 

    // First let's show that we can recover the types: 
    println(xs.map(_.actualType)) 

    i.tree match { 
     case Literal(Constant(index: Int)) => xs.lift(index).getOrElse(
     c.abort(c.enclosingPosition, "Invalid index!") 
    ) 
     case _ => c.abort(c.enclosingPosition, "Need a literal index!") 
    } 
    } 
} 

そして:推論種類が正確で正しいこと

scala> Demo.at(1, 'b, "c", 'd')(1) 
List(Int(1), Symbol, String("c"), Char('d')) 
res0: Symbol = 'b 

scala> Demo.at(1, 'b, "c", 'd')(2) 
List(Int(1), Symbol, String("c"), Char('d')) 
res1: String = c 

注。

引数が_*型の帰属を持つシーケンスであれば、これはうまくいかないことに注意してください。このケースをキャッチして便利なものを提供するには、次のような記述が必要ですエラーメッセージ:

def at_impl(c: Context)(xs: c.Expr[Any]*)(i: c.Expr[Int]) = { 
    import c.universe._ 

    xs.toList.map(_.tree) match { 
    case Typed(_, Ident(tpnme.WILDCARD_STAR)) :: Nil => 
     c.abort(c.enclosingPosition, "Needs real varargs!") 
    case _ => 
     i.tree match { 
     case Literal(Constant(index: Int)) => xs.lift(index).getOrElse(
      c.abort(c.enclosingPosition, "Invalid index!") 
     ) 
     case _ => c.abort(c.enclosingPosition, "Need a literal index!") 
     } 
    } 
} 

は、より多くの議論のための私の質問hereとバグレポートhereを参照してください。

関連する問題