gpt4 book ai didi

Scala:为反射/运行时实例使用正确的类型类实例

转载 作者:行者123 更新时间:2023-12-02 03:00:15 25 4
gpt4 key购买 nike

我有一个简单的特质

trait BusinessObject {}

和一个简单的类型类
trait Printer[T<:BusinessObject] { def print(instance:T): Unit }

在我的代码库中,我有几百个 BusinessObject 的实现。 .有些是直接实现者,有些实现了 BusinessObject 的子特征,还有一些使用 with 添加各种混合特征.我有大约 10 种不同的 Printer 的特殊实现。 (定义在各种子特征和混入中),以及任何其他 BusinessObject 的低优先级通用回退实例它很有魅力。

我需要记录 BusinessObject 的所有实现在代码库中,所以我使用了 Scala 的反射机制来枚举这些,现在想在每个上应用一个打印机。反射机制的方法签名是
def enumerateBOs: Traversable[BusinessObject]

它返回每个 BusinessObject 的一个实例执行。我的问题是,在运行时似乎没有办法为这个遍历中的每个对象获得正确的(特定的)打印机。

我试过用 .type 召唤像这样:
enumerateBOs.head match { case bo => Printer[bo.type].print(bo) }

但我得到了通用后备 Printer对于每个元素。

有什么方法可以做我想做的事吗?或者,如果隐式确实仅在编译时可用,则可以通过某种方式列出 BusinessObject 的所有实现者在编译时?

最佳答案

隐式(如 Scala 中的所有泛型)实际上是一种编译时机制,并且不可能在编译时定位非密封特征的所有实现。

话虽如此,在运行时运行 Scala 编译器并不难。

获取您的依赖项:

libraryDependencies ++= Seq(
"org.scala-lang" % "scala-reflect" % "2.12.3",
"org.scala-lang" % "scala-compiler" % "2.12.3"
)

您只需要一个 ToolBox对象来完成所有事情 - 它解析一个字符串,然后将解析后的树编译成一个函数 () => Any ,当被调用时,给出一个表达式的结果。代码也无法访问周围的上下文,因此所有类型都必须完全限定或导入。
import scala.reflect.runtime._
import scala.tools.reflect.ToolBox
import scala.util.Try

def unsafeCompile[A](code: String): A = {
val tb = currentMirror.mkToolBox()
tb.compile(tb.parse(code))().asInstanceOf[A]
}

上面的函数抛出异常,并没有真正检查是否强制转换为 A是一个有效的,所以你可以得到 ClassCastException如果使用不当,s 在未知的地方。

但是现在,在运行时获取实例只是几个 LOC 的问题:
enumerateBOs.map { obj =>
Try {
val f = unsafeCompile[Any => Unit](s"""
import your.package_.with_.Printer
// any additional imports for instances go there too

implicitly[Printer[_root_.${obj.getClass.getCanonicalName}]].print _
""")
f(obj)
}
}

我假设您没有使用匿名类 - 他们的 getCanonicalName返回 null在这种情况下你需要一些后备。它也相当缓慢。

关于Scala:为反射/运行时实例使用正确的类型类实例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46561577/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com