2017-06-19 35 views
1

鉴于以下字符串:使用Scala的反射来编译和加载对象

"println(\"Hello\")" 

,能够使用反射来评估代码,如下所示。

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

但是,可以说,该字符串包含一个函数定义的对象,如:

​​

是否有使用Scala的反射编译字符串,加载和运行的一种方式功能?我曾试图做的工作没有奏效,如果有人有一些示例代码,非常感谢。

+0

尝试quasiquote? –

回答

0

这取决于您如何严格定义可接受的输入字符串。该物体是否总是被称为MyObj?该方法应该总是被称为getX?它应该总是1方法还是可以是多个?

对于更一般的情况,您可以尝试从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