使用 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 反射编译和加载对象的主要内容,如果未能解决你的问题,请参考以下文章