scala - 是否可以定义一个带有可变参数的宏,并为每个参数获取一个类型?

标签 scala macros scala-2.10 scala-macros

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

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

我们可以用类似的方式定义一个宏:
def funImpl(c: Context)(xs: c.Expr[Any]*) = ???

fun(1,"1",1.0)

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

最佳答案

当然——例如:

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

请注意,推断的类型是精确且正确的。

另请注意,如果参数是带有 _* 的序列,这将不起作用。当然,键入 ascription,如果您想捕获这种情况并提供有用的错误消息,则需要编写如下内容:
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更多讨论。

关于scala - 是否可以定义一个带有可变参数的宏,并为每个参数获取一个类型?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17386824/

相关文章:

scala - 'sbt' 能否完成类似 'makefile' 的功能

scala - 如何在Spark中的执行器之间同步功能以避免在写入Elastic时并发

c - isalnum 等效于使用#define

c - 定义预处理器宏 swap(t, x, y)

java - 如何使用 apache poi XSSF 获取 xlsx 文件的文件名?

ScalaTest 抛出通过测试异常消息

scala - 选项列表 : equivalent of sequence in Scala?

function - 有没有办法在 MATLAB 中执行函数内联?

scala - Reifying 函数实现而不是引用

scala - 获取调用类