将变量转换为Scala“运行时评估”中的方法

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了将变量转换为Scala“运行时评估”中的方法相关的知识,希望对你有一定的参考价值。

我想评估一个在scala中作为变量字符串传递的函数(抱歉,但我是scala的新手)

def concate(a:String,b:String): String ={
  a+" "+b
}
var func="concate" //i'll get this function name from config as string 

我想表现得像

eval(func("hello","world)) //Like in Python 

所以输出就像

你好,世界

最终我想在来自我的配置的字符串上执行很少的内置函数,我不想在代码中硬编码函数名。

编辑

为了更清楚我的确切用法我有一个Config文件,其中定义了多个函数,它们是Data frame application.conf上的Spark内置函数。

  transformations = [
  {
    "table" : "users",
    "function" : "from_unixtime",
    "column" : "epoch"
  },
  {
    "table" : "users",
    "function" : "yearofweek",
    "column" : "epoch"
  }
]

现在函数yearofweek和from_unixtime是Spark内置函数,现在我想通过config中定义的函数来评估我的Dataframe。 #all函数应用于定义的列。 显而易见的方法是写一个if else和do字符串比较调用一个特定的内置函数,但这是很多..我正在寻找一个更好的解决方案。

答案

这在scala中确实是可能的,因为scala是符合JSR 223的脚本语言。这是一个例子(使用scala 2.11.8运行)。请注意,您需要导入您的方法,否则解释器将找不到它:

package my.example

object EvalDemo {

  // evalutates scala code and returns the result as T
  def evalAs[T](code: String) = {
    import scala.reflect.runtime.currentMirror
    import scala.tools.reflect.ToolBox
    val toolbox = currentMirror.mkToolBox()
    import toolbox.{eval, parse}
    eval(parse(code)).asInstanceOf[T]
  }

  def concate(a: String, b: String): String = a + " " + b

  def main(args: Array[String]): Unit = {

    var func = "concate" //i'll get this function name from config as string

    val code =
      s"""
         |import my.example.EvalDemo._
         |${func}("hello","world")
         |""".stripMargin

    val result: String = evalAs[String](code)

    println(result) // "hello world"
  }
}
另一答案

具有在代码中命名映射的函数

def foo(str: String) = str + ", foo"
def bar(str: String) = str + ", bar"

val fmap = Map("foo" -> foo _, "bar" -> bar _)

fmap("foo")("hello")

现在基于我们从配置中获取的函数名称,将名称传递给映射并查找相应的函数并调用其上的参数。

Repl规模

scala> :paste
// Entering paste mode (ctrl-D to finish)

def foo(str: String) = str + ", foo"
def bar(str: String) = str + ", bar"

val fmap = Map("foo" -> foo _, "bar" -> bar _)

fmap("foo")("hello")


// Exiting paste mode, now interpreting.

foo: (str: String)String
bar: (str: String)String
fmap: scala.collection.immutable.Map[String,String => String] = Map(foo -> $$Lambda$1104/1335082762@778a1250, bar -> $$Lambda$1105/841090268@55acec99)
res0: String = hello, foo
另一答案

Spark为您提供了一种使用SQL编写转换或查询的方法。因此,在这种情况下,您真的不必担心Scala函数,转换和评估。您只需要解析配置以生成SQL查询。

假设您已经使用Spark注册了一个表users,并希望根据提供的配置进行选择和转换,

// your generated query will look like this,
val query = "SELECT from_unixtime(epoch) as time, weekofyear(epoch) FROM users"

val result = spark.sql(query)

所以,你需要做的就是 - 从你的配置构建query

以上是关于将变量转换为Scala“运行时评估”中的方法的主要内容,如果未能解决你的问题,请参考以下文章

sizeof 是在编译时还是运行时评估?

如何判断表达式是在编译时还是运行时评估的?

python 模型运行时评估

Django:让 ModelChoiceField 在运行时评估查询集

重学scala:scala中的变量方法函数

Scala隐式转换