【问题标题】:Is it possible to define a macro with variadic parameters, and get a type for each parameter?是否可以使用可变参数定义宏,并为每个参数获取类型?
【发布时间】:2013-06-27 12:46:50
【问题描述】:

下面是一个明显的变参函数:

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

我们可以用类似的方式定义一个宏:

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

fun(1,"1",1.0)

但在这种情况下,所有参数都输入为Any。事实上,编译器在编译时就知道类型,但对我们隐藏了它。是否可以在宏中获取参数列表它们的类型?

【问题讨论】:

    标签: scala macros scala-2.10 scala-macros


    【解决方案1】:

    当然——例如:

    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 以获得更多讨论。

    【讨论】:

      猜你喜欢
      • 2014-12-15
      • 2010-12-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多