Scala宏调用编译时确定的函数名称

问题描述

我有以下代码

def invokeFunction(logger: Logger,fName: String) = macro invokeFunctionImpl

//...

def invokeFunctionImpl(c: Context)(logger: c.Expr[Logger],fName: c.Expr[String]) ={
  import c.universe._
  // i'd like to invoke: logger.${fName}("some message")
}

我面临的另一个问题是在编译期间使用给定参数为函数命名:

def createFunction(fName: String) = macro createFunctionImpl

//...

def createFunctionImpl(c: Context)(fName: c.Expr[String],param: c.Expr[String]) ={
  import c.universe._
  // i'd like to create: def functionNamed${fName}(param: [paramType]) = {
    // implementation unimportant
}

任何帮助将不胜感激。

解决方法

invokeFunction应该像

def invokeFunction(logger: Logger,fName: String): Unit = macro invokeFunctionImpl

def invokeFunctionImpl(c: blackbox.Context)(logger: c.Expr[Logger],fName: c.Expr[String]): c.Expr[Unit] ={
  import c.universe._
  val q"${fNameStr: String}" = fName.tree
  c.Expr(q"""$logger.${TermName(fNameStr)}("some message")""")
}

我添加了返回类型。我假设fName是编译时的String文字(否则您将拥有MatchError)。

关于createFunction尝试

def createFunction(fName: String,param: String): Unit = macro createFunctionImpl

def createFunctionImpl(c: blackbox.Context)(fName: c.Expr[String],param: c.Expr[String]): c.Expr[Unit] ={
  import c.universe._
  val q"${fNameStr: String}" = fName.tree
  val q"${paramNameStr: String}" = param.tree

  c.Expr(q"""
    def ${TermName(fNameStr)}(${TermName(paramNameStr)}: ParamType) = ???

    ()
  """)
}

请注意,宏的签名及其实现必须相互对应。所以我在param上添加了createFunction。并且我添加了返回类型。同样重要的是,要创建的函数只能在宏扩展到的块内访问。新定义不是def macros的原意(macro annotations是)。

我不确定我是否完全了解您在做什么。如果您提供了如何使用宏的代码,则答案会更容易。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...