scala – 是否可以使用可变参数定义宏,并获取每个参数的类型?
发布时间:2020-12-16 18:55:39 所属栏目:安全 来源:网络整理
导读:以下是一个明显的可变函数: def fun(xs: Any*) = ??? 我们可以用类似的方式定义一个宏: def funImpl(c: Context)(xs: c.Expr[Any]*) = ???fun(1,"1",1.0) 但在这种情况下,所有参数都输入为Any.实际上,编译器在编译时知道类型,但是将它隐藏起来.是否有可能
以下是一个明显的可变函数:
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,'d')(2) List(Int(1),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. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |