使用 Scala 反射 API 获取内部模块的伴随对象实例 [英] Get the companion object instance of a inner modul with the Scala reflection API

查看:40
本文介绍了使用 Scala 反射 API 获取内部模块的伴随对象实例的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我实现了获取伴随对象实例中提到的代码新的 Scala 反射 API(来自此处的代码 https://gist.github.com/xeno-by/4985929).

I implemented the code mentioned in Get companion object instance with new Scala reflection API (code from here https://gist.github.com/xeno-by/4985929).

object Reflection {
    def getCompanionObject(caseclassinstance:Product):Any = {
        import scala.reflect.runtime.{currentMirror => cm}
        val classSymbol = cm.classSymbol(caseclassinstance.getClass)
        val moduleSymbol = classSymbol.companionSymbol.asModule
        val moduleMirror = cm.reflectModule(moduleSymbol)
        moduleMirror.instance
    }
}

这适用于任何标准类的案例类.不幸的是,在项目的某些类中,我得到了一个异常:scala.ScalaReflectionException: object Tensor is an internal module, use reflectModule on an InstanceMirror 来获取它的 ModuleMirror 异常很清楚,所以我试图改变我的代码如下:

This works fine for any standard class of case classes. Unfortunately in some classes of the project I get an Exception: scala.ScalaReflectionException: object Tensor is an inner module, use reflectModule on an InstanceMirror to obtain its ModuleMirror The exception is pretty clear, so I tried to change my code as follows:

object Reflection {
    def getCompanionObject(caseclassinstance:Product):Any = {
        import scala.reflect.runtime.{currentMirror => cm}
        val classSymbol = cm.classSymbol(caseclassinstance.getClass)
        val moduleSymbol = classSymbol.companionSymbol.asModule
        val instanceMirror = cm.reflect(caseclassinstance)
        val moduleMirror = instanceMirror.reflectModule(moduleSymbol)
        moduleMirror.instance
    }
}

但现在我得到一个 scala.ScalaReflectionException: expected a member of class Tensor, you provide object Prototype2.SPL.SPL_Exp.Tensor 我没有找到如何更改代码来解决这个问题.非常感谢任何帮助!

But now I get a scala.ScalaReflectionException: expected a member of class Tensor, you provided object Prototype2.SPL.SPL_Exp.Tensor and I did not find out how to change the code to fix this. Any help is greatly appreciated!

更新:我提供了一些代码以提高重现性:

Update: I provide some code for better reproducibility:

scala> trait SPL {
     | case class Tensor()
     | }
defined trait SPL

scala> val s = new SPL {}
s: SPL = $anon$1@165f5a4

scala> val t = s.Tensor()
t: s.Tensor = Tensor()

scala> object Reflection { /* as in the first code snippet*/}
defined module Reflection

scala> Reflection.getCompanionObject(t)
scala.ScalaReflectionException: object Tensor is an inner module, use reflectModule on an InstanceMirror to obtain its ModuleMirror
...

scala> object Reflection { /* as in the second code snippet*/}
defined module Reflection

scala> Reflection.getCompanionObject(t)
scala.ScalaReflectionException: expected a member of class Tensor, you provided object SPL.Tensor
...

推荐答案

你应该有一个模块的实例.您只能从 Spl 的镜像中获取 Tensor 符号的镜像.

You should have an instance of module. You can get mirror for Tensor symbol only from mirror of Spl.

trait Spl {
  case class Tensor(s: String)
}

val spl = new Spl {}

val t = spl.Tensor("T")

// mirror for module spl
val moduleMirror = cm.reflect(spl)
// class symbol for Tensor
val instanceSymbol = cm.classSymbol(t.getClass)
// symbol for companion object
val companionSymbol = instanceSymbol.companionSymbol.asModule
// mirror for companion object symbol in spl module mirror
val companionMirror = moduleMirror.reflectModule(companionSymbol)

scala> companionMirror.instance
res0: Any = Tensor

你可以使用一些丑陋的魔法获得一个 Spl 的实例:

You could get an instance of Spl using a bit of ugly magic:

val outer =
  t.
  getClass.
  getFields.
  find(_.getName == """$outer""").
  get.
  get(t)

在可以之前不要这样做.

You should not do so until you can.

def getCompanionObject(t: Product):Any = {
  import scala.reflect.runtime.{currentMirror => cm}
  val outerField = t.getClass.getFields.find(_.getName == """$outer""")
  val moduleMirror = outerField.map{ _.get(t) }.map{ cm.reflect(_) }
  val instanceSymbol = cm.classSymbol(t.getClass)
  val companionSymbol = instanceSymbol.companionSymbol.asModule
  val companionMirror =
    moduleMirror.
      map{ _.reflectModule(companionSymbol) }.
      getOrElse{ cm.reflectModule(companionSymbol) }
  companionMirror.instance
}

这篇关于使用 Scala 反射 API 获取内部模块的伴随对象实例的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆