使用新的 Scala 反射 API 获取伴生对象实例
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/11020746/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Get companion object instance with new Scala reflection API
提问by leedm777
With Scala's new reflection API, is it possible to get a reference to a class's companion object? I am thinking something along these lines:
使用 Scala 的新反射 API,是否可以获得对类的伴随对象的引用?我在想这些事情:
trait Base {
def companion: MetaBase = someReflectionMagic(this).asInstanceOf[MetaBase]
}
trait MetaBase {
// stuff
}
// ---
class Foo extends Base
object Foo extends MetaBase
assert(new Foo.companion == Foo)
回答by Eugene Burmako
Dave! Thanks for being interested in the new reflection. Early adopters have driven the development process of reflection and macros to a significant extent, and I'm very happy about being a part of our amazing community.
戴夫!感谢您对新反射感兴趣。早期采用者在很大程度上推动了反射和宏的开发过程,我很高兴成为我们令人惊叹的社区的一员。
Before answering your question, I'd like to start with a disclaimer. In 2.10.0-M4 we have just laid the foundations of the Scala reflection API. It's still hot off the press, so the docs are very scarce and the API isn't exactly riddled with conveniences. It works, but it requires testing and feedback. Sure, messing with pre-release APIs is troublesome, but I'm always here to help.
在回答您的问题之前,我想先声明一下。在 2.10.0-M4 中,我们刚刚奠定了 Scala 反射 API 的基础。它仍然很火爆,所以文档非常稀缺,而且 API 并没有完全充斥着各种便利。它有效,但需要测试和反馈。当然,弄乱预发布的 API 很麻烦,但我总是在这里提供帮助。
So far we have a draft of what will in the future become the reflection SIP: https://docs.google.com/document/d/1Z1VhhNPplbUpaZPIYdc0_EUv5RiGQ2X4oqp0i-vz1qw/edit#heading=h.pqwdkl1226tc. You can read it right away, or can first skim through my answer below.
到目前为止,我们已经有了一份未来将成为反射 SIP 的草案:https: //docs.google.com/document/d/1Z1VhhNPplbUpaZPIYdc0_EUv5RiGQ2X4oqp0i-vz1qw/edit#heading=h.pqwdkl1226tc。您可以立即阅读,也可以先浏览下面我的回答。
trait Base {
def companion: MetaBase = {
// runtime reflection is typically done
// by importing things from scala.reflect.runtime package
import scala.reflect.runtime._
// the new Scala reflection API is mirror based
// mirrors constitute a hierarchy of objects
// that closely follows the hierarchy of the things they reflect
// for example, for a class you'll have a ClassMirror
// for a method you'll have a MethodMirror and so on
// why go the extra mile?
// because this provides more flexibility than traditional approaches
// you can read more about mirror-based designs here:
// https://dl.dropbox.com/u/10497693/Library/Computer%20Science/Metaprogramming/Reflection/mirrors.pdf
// https://dl.dropbox.com/u/10497693/Library/Computer%20Science/Metaprogramming/Reflection/reflecting-scala.pdf
// bottom line is that to do anything you will need a mirror
// for example, in your case, you need a ClassMirror
// remember I said that mirrors provide more flexibility?
// for one, this means that mirror-based reflection facilities
// might have multiple implementations
// in a paper linked above, Gilad Bracha muses over a runtime
// that loads things remotely over the network
// in our case we might have different mirrors for JVM and CLR
// well, anyways
// the canonical (and the only one now) implementation of the mirror API
// is Java-based reflection that uses out of the box classloaders
// here's its root: https://github.com/scalamacros/kepler/blob/9f71e9f114c10b52350c6c4ec757159f06e55daa/src/reflect/scala/reflect/api/Mirrors.scala#L178
// yeah, right, I've just linked a source file from trunk
// we'll have Scaladocs for that soon, but for now take a look
// this file is interfaces-only and is heavy on comments
// to start with Java-based reflection implementation you need a classloader
// let's grab one and instantiate the root mirror
// btw, the same effect could be achieved by writing
// `scala.reflect.runtime.currentMirror`
val rootMirror = universe.runtimeMirror(getClass.getClassLoader)
// now when we've finally entered the reflective world
// we can get the stuff done
// first we obtain a ClassSymbol that corresponds to the current instance
// (ClassSymbols are to Scala the same as Classes are to Java)
var classSymbol = rootMirror.classSymbol(getClass)
// having a Scala reflection entity
// we can obtain its reflection using the rootMirror
val classMirror = rootMirror.reflectClass(classSymbol)
// now we just traverse the conceptual hierarchy of mirrors
// that closely follows the hierarchy of Scala reflection concepts
// for example, a ClassMirror has a companion ModuleMirror and vice versa
val moduleMirror = classMirror.companion.get
// finally, we've arrived at our destination
moduleMirror.instance.asInstanceOf[MetaBase]
}
}
trait MetaBase {
// stuff
}
// ---
class Foo extends Base
object Foo extends MetaBase
object Test extends App {
assert(new Foo().companion == Foo)
}
Update. Please also see the excellent post by Daniel Sobral: http://dcsobral.blogspot.ch/2012/07/json-serialization-with-reflection-in.html.
更新。另请参阅 Daniel Sobral 的精彩帖子:http: //dcsobral.blogspot.ch/2012/07/json-serialization-with-reflection-in.html。
回答by piotrga
I didn't see Eugene's last comment and came up with this. It works for scala 2.10.
我没有看到 Eugene 的最后一条评论并想出了这个。它适用于 Scala 2.10。
trait ReflectionSugars{
import scala.reflect.runtime.{universe => ru}
private lazy val universeMirror = ru.runtimeMirror(getClass.getClassLoader)
def companionOf[T](implicit tt: ru.TypeTag[T]) = {
val companionMirror = universeMirror.reflectModule(ru.typeOf[T].typeSymbol.companionSymbol.asModule)
companionMirror.instance
}
}
trait X extends ReflectionSugars{
def companion = companionOf[X]
}
https://gist.github.com/piotrga/5928581
https://gist.github.com/piotrga/5928581
I hope this helps!
我希望这有帮助!

