在 Scala 中将变量转换为方法 "Runtime Evaluation"
Casting a variable to a method in Scala "Runtime Evaluation"
我想评估在 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
所以输出会像
hello world
最终我想对来自我的配置的字符串执行一些内置函数,我不想在代码中对函数名称进行硬编码。
EDIT
更清楚我的确切用例
我有一个配置文件,其中定义了多个函数,这些函数是数据框上的 Spark 内置函数
application.conf 看起来像
transformations = [
{
"table" : "users",
"function" : "from_unixtime",
"column" : "epoch"
},
{
"table" : "users",
"function" : "yearofweek",
"column" : "epoch"
}
]
现在函数 yearofweek 和 from_unixtime 是 Spark 内置函数,现在我想通过配置中定义的函数来评估我的 Dataframe。 #所有函数都应用于定义的列。
显而易见的方法是编写一个 if else 并调用特定的内置函数进行字符串比较,但这是很多方式..
我正在寻找更好的解决方案。
代码中有名称映射的功能
def foo(str: String) = str + ", foo"
def bar(str: String) = str + ", bar"
val fmap = Map("foo" -> foo _, "bar" -> bar _)
fmap("foo")("hello")
现在根据我们从配置中获取的函数名称,将名称传递给地图并查找相应的函数并调用其参数。
Scala 响应
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 -> $$Lambda04/1335082762@778a1250, bar -> $$Lambda05/841090268@55acec99)
res0: String = hello, foo
Spark 为您提供了一种使用 SQL 编写转换或查询的方法。所以,在这种情况下,您真的不必担心 Scala 函数、转换和求值。您只需解析您的配置以生成 SQL 查询。
假设您已经使用 Spark 注册了一个 table users
并且想要根据提供的配置进行 select 和转换,
// 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 中确实是可能的,因为 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"
}
}
我想评估在 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
所以输出会像
hello world
最终我想对来自我的配置的字符串执行一些内置函数,我不想在代码中对函数名称进行硬编码。
EDIT
更清楚我的确切用例 我有一个配置文件,其中定义了多个函数,这些函数是数据框上的 Spark 内置函数 application.conf 看起来像
transformations = [
{
"table" : "users",
"function" : "from_unixtime",
"column" : "epoch"
},
{
"table" : "users",
"function" : "yearofweek",
"column" : "epoch"
}
]
现在函数 yearofweek 和 from_unixtime 是 Spark 内置函数,现在我想通过配置中定义的函数来评估我的 Dataframe。 #所有函数都应用于定义的列。
显而易见的方法是编写一个 if else 并调用特定的内置函数进行字符串比较,但这是很多方式..
我正在寻找更好的解决方案。
代码中有名称映射的功能
def foo(str: String) = str + ", foo"
def bar(str: String) = str + ", bar"
val fmap = Map("foo" -> foo _, "bar" -> bar _)
fmap("foo")("hello")
现在根据我们从配置中获取的函数名称,将名称传递给地图并查找相应的函数并调用其参数。
Scala 响应
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 -> $$Lambda04/1335082762@778a1250, bar -> $$Lambda05/841090268@55acec99)
res0: String = hello, foo
Spark 为您提供了一种使用 SQL 编写转换或查询的方法。所以,在这种情况下,您真的不必担心 Scala 函数、转换和求值。您只需解析您的配置以生成 SQL 查询。
假设您已经使用 Spark 注册了一个 table users
并且想要根据提供的配置进行 select 和转换,
// 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 中确实是可能的,因为 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"
}
}