2013-06-30 20 views
6

Poniżej jest oczywiste, o zmiennej liczbie argumentów funkcja:Czy można zdefiniować makro z parametrami variadic i uzyskać typ dla każdego parametru?

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

Możemy zdefiniować makro w podobny sposób:

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

fun(1,"1",1.0) 

Ale w tym przypadku, wszystkie argumenty są wpisane jako Any. W rzeczywistości kompilator zna typy podczas kompilacji, ale ukrywa je przed nami. Czy można uzyskać listę argumentów w typach makr?

Odpowiedz

6

Sure-na przykład:

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!") 
    } 
    } 
} 

A potem:

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 

Uwaga wywnioskować, że typy są dokładne i prawidłowe.

Należy również zauważyć, że to nie zadziała, jeśli argument jest sekwencją z przypisaniem typu _*, i że musisz napisać coś takiego, jeśli chcesz uchwycić tę sprawę i podać przydatne informacje. komunikat o błędzie:

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!") 
     } 
    } 
} 

Zobacz moje pytanie here i zgłoszenia here więcej dyskusji.