2013-06-30 16 views
6

Il seguente è un ovvio Funzione Variadica:È possibile definire una macro con parametri variadici e ottenere un tipo per ciascun parametro?

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

possiamo definire una macro in modo simile:

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

fun(1,"1",1.0) 

Ma in questo caso, tutti gli argomenti vengono digitati come Any. In effetti, il compilatore conosce i tipi in fase di compilazione, ma lo nasconde da noi. È possibile ottenere un elenco di argomenti e i loro tipi in una macro?

risposta

6

Certo, ad esempio:

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

E poi:

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 

Nota che i tipi dedurre sono precise e corrette.

Nota anche che questo non funzionerà se l'argomento è una sequenza con l'attribuzione di tipo _*, ovviamente, e che dovrai scrivere qualcosa come il seguente se vuoi catturare questo caso e fornire un utile messaggio di errore:

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

Vedi la mia domanda here e bug rapporto here per ulteriori discussioni.

Problemi correlati