使用 Scala 反射编译和加载对象

Posted

技术标签:

【中文标题】使用 Scala 反射编译和加载对象【英文标题】:Using Scala reflection to compile and load object 【发布时间】:2017-06-19 09:38:19 【问题描述】:

给定以下字符串:

"println(\"Hello\")"

可以使用反射来评估代码,如下所示。

object Eval 
  def apply[A](string: String): A = 
    val toolbox = currentMirror.mkToolBox()
    val tree = toolbox.parse(string)
    toolbox.eval(tree).asInstanceOf[A]
  

但是,假设字符串包含一个具有函数定义的对象,例如:

"""object MyObj  def getX="X""""

有没有办法使用 Scala 反射来编译字符串、加载它并运行函数?我尝试做的没有奏效,如果有人有一些示例代码,非常感谢。

【问题讨论】:

试试准引用? 【参考方案1】:

这取决于您定义可接受的输入字符串的严格程度。该对象是否应始终称为MyObj?该方法是否应始终称为getX?它应该始终是一种方法还是可以是多种方法?

对于更一般的情况,您可以尝试从 AST 中提取所有方法名称并生成对每个方法的调用。以下代码将调用每个方法(并返回最后一个方法的结果),该方法在某些对象中接受 0 个参数且不是构造函数,不考虑继承:

def eval(string: String): Any = 
  val toolbox = currentMirror.mkToolBox()
  val tree = toolbox.parse(string)
  //oName is the name of the object
  //defs is the list of all method definitions
  val ModuleDef(_,oName,Template(_,_,defs)) = tree
  //only generate calls for non-constructor, zero-arg methods
  val defCalls = defs.collect 
    case DefDef(_,name,_,params,_,_) 
      if name != termNames.CONSTRUCTOR && params.flatten.isEmpty => q"$oName.$name"
  
  //put the method calls after the object definition
  val block = tree :: defCalls
  toolbox.eval(q"..$block")

并使用它:

scala> eval("""object MyObj  def bar() = println("bar"); def foo(a: String) = println(a); def getX = "x" """)
bar
res60: Any = x

【讨论】:

以上是关于使用 Scala 反射编译和加载对象的主要内容,如果未能解决你的问题,请参考以下文章

反射机制

Java中类加载机制和反射技术

反射

JAVA反射总结

java反射--动态加载

反射和代理