2013-06-30 39 views
6

Sau đây là một chức năng variadic rõ ràng:Có thể xác định macro bằng tham số variadic và nhận loại cho mỗi tham số không?

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

Chúng ta có thể định nghĩa một macro trong một cách tương tự:

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

fun(1,"1",1.0) 

Nhưng trong trường hợp này, tất cả các đối số được gõ như Any. Trong thực tế, trình biên dịch biết các loại tại thời gian biên dịch, nhưng ẩn nó khỏi chúng ta. Có thể lấy danh sách đối số loại của chúng trong macro không?

Trả lời

6

chắc-ví dụ:

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

Và sau đó:

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 

Lưu ý rằng các loại suy ra là chính xác và đúng đắn. Lưu ý rằng điều này sẽ không hoạt động nếu đối số là một chuỗi với kiểu ghi là _*, tất nhiên, và bạn sẽ cần phải viết một cái gì đó như sau nếu bạn muốn bắt trường hợp này và cung cấp một hữu ích thông báo lỗi:

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

Xem tôi câu hỏi here và report bug here để thảo luận nhiều hơn nữa.