用准斯卡拉法评估复杂类型,不提升



>我需要编译函数,然后用List[Map[String, AnyRef]]类型的不同参数对其进行评估。 我有以下代码,它不使用这种类型进行编译,而是使用List[Int]等简单类型进行编译。

我发现Liftablescala.reflect.api.StandardLiftables.StandardLiftableInstances中只有某些实现

import scala.reflect.runtime.universe
import scala.reflect.runtime.universe._
import scala.tools.reflect.ToolBox

val tb = universe.runtimeMirror(getClass.getClassLoader).mkToolBox()
val functionWrapper =
"""
object FunctionWrapper {
def makeBody(messages: List[Map[String, AnyRef]]) = Map.empty
}""".stripMargin
val functionSymbol = 
tb.define(tb.parse(functionWrapper).asInstanceOf[tb.u.ImplDef])
val list: List[Map[String, AnyRef]] = List(Map("1" -> "2"))
tb.eval(q"$functionSymbol.function($list)")

为此出现编译错误,如何使其工作?

Error:(22, 38) Can't unquote List[Map[String,AnyRef]], consider using 
... or providing an implicit instance of 
Liftable[List[Map[String,AnyRef]]]
tb.eval(q"$functionSymbol.function($list)")
^

问题不是来自复杂类型,而是来自尝试使用AnyRef。当您取消引用某些文字时,这意味着您希望基础结构能够创建有效的语法树,以创建与您传递的对象完全匹配的对象。不幸的是,这显然不可能适用于所有对象。例如,假设您已将对Thread.currentThread()的引用作为Map的一部分传递。它怎么可能工作?编译器只是无法重新创建如此复杂的对象(更不用说使其成为当前线程了)。因此,您有两个明显的选择:

  1. 让你的论点也成为Tree,即像这样的东西
def testTree() = {
val tb = universe.runtimeMirror(getClass.getClassLoader).mkToolBox()
val functionWrapper =
"""
|  object FunctionWrapper {
|
|    def makeBody(messages: List[Map[String, AnyRef]]) = Map.empty
|
|  }
""".stripMargin
val functionSymbol =
tb.define(tb.parse(functionWrapper).asInstanceOf[tb.u.ImplDef])
//val list: List[Map[String, AnyRef]] = List(Map("1" -> "2"))
val list = q"""List(Map("1" -> "2"))"""
val res = tb.eval(q"$functionSymbol.makeBody($list)")
println(s"testTree = $res")
}

这种方法的明显缺点是你在编译时松散了类型安全,并且可能需要为树工作提供大量上下文

  1. 另一种方法是不尝试将任何包含AnyRef的内容传递给编译器基础结构。这意味着您创建了一些类似函数的Wrapper
package so {
trait Wrapper {
def call(args: List[Map[String, AnyRef]]): Map[String, AnyRef]
}
}

然后让你生成的代码返回一个Wrapper而不是直接执行逻辑,并从通常的 Scala 代码而不是在编译的代码中调用Wrapper。像这样:

def testWrapper() = {
val tb = universe.runtimeMirror(getClass.getClassLoader).mkToolBox()
val functionWrapper =
"""
|object FunctionWrapper {
|  import scala.collection._
|  import so.Wrapper /* <- here probably different package :) */
|
|  def createWrapper(): Wrapper = new Wrapper {
|    override def call(args: List[Map[String, AnyRef]]): Map[String, AnyRef] = Map.empty
|  }
|}
| """.stripMargin

val functionSymbol = tb.define(tb.parse(functionWrapper).asInstanceOf[tb.u.ImplDef])
val list: List[Map[String, AnyRef]] = List(Map("1" -> "2"))
val tree: tb.u.Tree = q"$functionSymbol.createWrapper()"
val wrapper = tb.eval(tree).asInstanceOf[Wrapper]
val res = wrapper.call(list)
println(s"testWrapper = $res")
}

附言我不确定你在做什么,但要注意性能问题。Scala 是一种很难编译的语言,因此编译自定义代码可能比运行它花费更多时间。如果性能成为一个问题,您可能需要使用一些其他方法,例如成熟的宏代码生成或至少缓存已编译的代码。

相关内容

  • 没有找到相关文章

最新更新