2

我試圖以二進制方式解釋作爲字符串給出的代碼。 如:動態地解析一個字符串並使用反射和解釋器在scala中返回一個函數

val myString = "def f(x:Int):Int=x+1". 

進出口尋找,將返回真正的功能在它外面的方法: 如:

val myIncrementFunction = myDarkMagicFunctionThatWillBuildMyFunction(myString) 
println(myIncrementFunction(3)) 

將打印4

使用案例:我想用一些稍後在我的代碼中解釋代碼的簡單函數。例如,他們可以提供類似def fun(x:Int)的東西:Int = x + 1作爲字符串,然後我使用解釋器來編譯/執行代碼,然後我希望能夠使用這個fun(x )例如在地圖中。

問題是這個函數類型對我來說是未知的,這是一個很大的問題,因爲我需要從IMain退回。 我已經閱讀了關於反射,類型系統等的內容,並且經過一些Google搜索之後,我達到了這一點。我也檢查了twitter的util-eval,但是我不能從他們的測試中的文檔和示例中看到太多,這是非常相同的事情。

如果我知道我可以這樣做

val settings = new Settings 
val imain = new IMain(settings) 
val res = imain.interpret("def f(x:Int):Int=x+1; val ret=f _ ") 
val myF = imain.valueOfTerm("ret").get.asInstanceOf[Function[Int,Int]] 
println(myF(2)) 

其正常工作和印刷品3的類型,但我封鎖的問題,我上面說的,我不知道該函數的類型,而這這個例子的作用僅僅是因爲我在我定義字符串函數以測試IMain如何工作時使用的類型。

你知道我如何實現這個功能嗎?

我是新手,所以請原諒我,如果我寫了任何錯誤。

感謝

回答

0

好吧,我設法實現我想要的,我仍然在尋找改善該代碼的功能,但這個片段我想要做什麼。

我用Scala的工具箱和quasiquotes

import scala.reflect.runtime.universe.{Quasiquote, runtimeMirror} 
import scala.tools.reflect.ToolBox 

object App { 
    def main(args: Array[String]): Unit = { 
     val mirror = runtimeMirror(getClass.getClassLoader) 
     val tb = ToolBox(mirror).mkToolBox() 

     val data = Array(1, 2, 3) 

     println("Data before function applied on it") 
     println(data.mkString(",")) 


     println("Please enter the map function you want:") 
     val function = scala.io.StdIn.readLine() 
     val functionWrapper = "object FunctionWrapper { " + function + "}" 
     val functionSymbol = tb.define(tb.parse(functionWrapper).asInstanceOf[tb.u.ImplDef]) 

     // Map each element using user specified function 
     val dataAfterFunctionApplied = data.map(x => tb.eval(q"$functionSymbol.function($x)")) 

     println("Data after function applied on it") 
     println(dataAfterFunctionApplied.mkString(",")) 
    } 
} 

這裏是結果在終端:

Data before function applied on it 
1,2,3 
Please enter the map function you want: 
def function(x: Int): Int = x + 2 
Data after function applied on it 
3,4,5 

Process finished with exit code 0 
+0

只是要添加。另外,很棒的答案,更多的上下文可以在http://docs.scala-lang.org/overviews/quasiquotes/usecases找到。要轉換爲可應用的函數,請使用以下內容:val data = tb.eval(q「$ functionSymbol.f _」)。asInstanceOf [Int => Int] –

2

您可以使用Twitter的UTIL庫要做到這一點,檢查測試文件: https://github.com/twitter/util/blob/develop/util-eval/src/test/scala/com/twitter/util/EvalTest.scala

如果您需要使用IMAIN,也許是因爲你想使用的intepreter與自己的自定義設置,你可以這樣做:

a。首先創建一個類來保存你的結果:

class ResHolder(var value: Any) 

b。創建一個容器對象來保存結果和解釋的代碼到該對象:

val settings = new Settings() 
    val writer = new java.io.StringWriter() 
    val interpreter = new IMain(settings, writer) 

    val code = "def f(x:Int):Int=x+1" 

    // Create a container object to hold the result and bind in the interpreter 
    val holder = new ResHolder(null) 

    interpreter.bind("$result", holder.getClass.getName, holder) match { 
     case Success => 
     case Error => throw new ScriptException("error in: binding '$result' value\n" + writer) 
     case Incomplete => throw new ScriptException("incomplete in: binding '$result' value\n" + writer) 
    } 

    val ir = interpreter.interpret("$result.value = " + code) 

    // Return cast value or throw an exception based on result 
    ir match { 
     case Success => 
      val any = holder.value 
      any.asInstanceOf[(Int) => Int] 

     case Error => throw new ScriptException("error in: '" + code + "'\n" + writer) 
     case Incomplete => throw new ScriptException("incomplete in :'" + code + "'\n" + writer) 
    } 
1

我想闡述以前answer與評論,並執行方案的評估:

import scala.reflect.runtime.universe.{Quasiquote, runtimeMirror} 
import scala.tools.reflect.ToolBox 

object Runtime { 

    def time[R](block: => R): R = { 
    val t0 = System.nanoTime() 
    val result = block // call-by-name 
    val t1 = System.nanoTime() 
    println("Elapsed time: " + (t1 - t0) + " ns") 
    result 
    } 

    def main(args: Array[String]): Unit = { 
     val mirror = runtimeMirror(getClass.getClassLoader) 
     val tb = ToolBox(mirror).mkToolBox() 
     val data = Array(1, 2, 3) 

     println(s"Data before function applied on it: '${data.toList}") 
     val function = "def apply(x: Int): Int = x + 2" 
     println(s"Function: '$function'") 
     println("#######################") 

     // Function with tb.eval 
     println(".... with tb.eval") 
     val functionWrapper = "object FunctionWrapper { " + function + "}" 
     // This takes around 1sec! 
     val functionSymbol = time { tb.define(tb.parse(functionWrapper).asInstanceOf[tb.u.ImplDef])} 

     // This takes around 0.5 sec! 
     val result = time {data.map(x => tb.eval(q"$functionSymbol.apply($x)"))} 
     println(s"Data after function applied on it: '${result.toList}'") 

     println(".... without tb.eval") 
     val func = time {tb.eval(q"$functionSymbol.apply _").asInstanceOf[Int => Int]} 
     // This takes around 0.5 sec! 
     val result2 = time {data.map(func)} 
     println(s"Data after function applied on it: '${result2.toList}'") 

    } 
} 

如果我們執行代碼a波夫我們看到下面的輸出:

Data before function applied on it: 'List(1, 2, 3) 
Function: 'def apply(x: Int): Int = x + 2' 
####################### 
.... with tb.eval 
Elapsed time: 716542980 ns 
Elapsed time: 661386581 ns 
Data after function applied on it: 'List(3, 4, 5)' 
.... without tb.eval 
Elapsed time: 394119232 ns 
Elapsed time: 85713 ns 
Data after function applied on it: 'List(3, 4, 5)' 

只是爲了強調的重要性做了評價,以提取功能,然後應用到數據,而最終再次評估,作爲答案的評論表示。

相關問題