通过给定的泛型类型 Scala 获取类的伴随对象
Posted
技术标签:
【中文标题】通过给定的泛型类型 Scala 获取类的伴随对象【英文标题】:Get companion object of class by given generic type Scala 【发布时间】:2012-02-28 16:12:40 【问题描述】:我要做的是创建一个函数,该函数将采用泛型类并在其中使用静态方法(对不起,Java 语言,我的意思是它的伴随对象的方法)。
trait Worker def doSth: Unit
class Base
object Base extends Worker
// this actually wouldn't work, just to show what I'm trying to achieve
def callSthStatic[T that companion object is <: Worker](implicit m: Manifest[T])
// here I want to call T.doSth (on T object)
m.getMagicallyCompanionObject.doSth
有什么想法吗?
【问题讨论】:
【参考方案1】:A gist by Miles Sabin可能会给你一个提示:
trait Companion[T]
type C
def apply() : C
object Companion
implicit def companion[T](implicit comp : Companion[T]) = comp()
object TestCompanion
trait Foo
object Foo
def bar = "wibble"
// Per-companion boilerplate for access via implicit resolution
implicit def companion = new Companion[Foo]
type C = Foo.type
def apply() = Foo
import Companion._
val fc = companion[Foo] // Type is Foo.type
val s = fc.bar // bar is accessible
如果使用 Scala 2.9.x,则应使用 -Ydependent-method-types
标志编译。
【讨论】:
我添加了实际的 Gist 内容 - Gist 可能会消失,并且只有链接才有资格作为评论。 我在“implicit def partner[T] (隐式comp:Companion [T])= comp()”与scala 2.9.1。我做错了吗? :-) 我会在括号中添加,如果类型Foo
是可见的,那么它的伴生对象也是可见的,所以虽然这看起来很漂亮,但我认为它在实践中没有用。
这是一个不错的技巧。我必须阅读一些有关依赖方法类型的信息,但这似乎有效!谢谢
如果没有“每个同伴样板”部分,有什么方法可以让它工作?【参考方案2】:
您可以使用反射来获取伴生类及其实例,但这依赖于 Scala 内部结构,这些内部结构可能会在遥远的(?)未来发生变化。当您获得 AnyRef 时,没有类型安全性。但是没有必要为你的类和对象添加任何隐式。
def companionOf[T : Manifest] : Option[AnyRef] = try
val classOfT = implicitly[Manifest[T]].erasure
val companionClassName = classOfT.getName + "$"
val companionClass = Class.forName(companionClassName)
val moduleField = companionClass.getField("MODULE$")
Some(moduleField.get(null))
catch
case e => None
case class A(i : Int)
companionOf[A].collectcase a : A.type => a(1)
// res1: Option[A] = Some(A(1))
【讨论】:
谢谢,反射会解决问题...直到 scala 版本更新,因为伴生对象的名称不承诺以这种方式保留。 嗯,没错。但我认为命名不会很快改变,因为这个约定至少从早期的 Scala 2.x 天开始就持续了。【参考方案3】:当我忘记如何执行此操作并且答案对我来说不是百分百满意时,我会一直点击此页面。以下是我如何处理反射:
val thisClassCompanion = m.reflect(this).symbol.companion.asModule
val structural = m.reflectModule(thisClassCompanion)
.instance.asInstanceOf[def doSth: Unit]
您可能需要验证该类实际上有一个伴生对象或伴生对象。asModule 将抛出反射异常不是模块
更新:为清楚起见添加了另一个示例:
object CompanionUtil
import scala.reflect.runtime.currentMirror => cm
def companionOf[T, CT](implicit tag: TypeTag[T]): CT =
Try[CT]
val companionModule = tag.tpe.typeSymbol.companion.asModule
cm.reflectModule(companionModule).instance.asInstanceOf[CT]
.getOrElse(throw new RuntimeException(s"Could not get companion object for type $tag.tpe"))
【讨论】:
什么是 m?你能举一个完整的例子吗?我正在寻找可以像这样使用的东西:abstract class Whatever[T] = val companion = companionOf[T]
m 是当前镜像,我只是将它重命名为 import import scala.reflect.runtime.currentMirror => m
请注意,CT
是伴随对象的类型,即T.type
,例如companionOf[Foo, Foo.type]
其中Foo
是具有伴随对象的类的名称。
根据答案,这里有一个获取指定类对象的伴生对象类型引用的方法:def companionOf[CT](clazz: Class[_]): CT = import scala.reflect.runtime.currentMirror => cm Try[CT] val companionModule = cm.classSymbol(clazz).companion.asModule cm.reflectModule(companionModule).instance.asInstanceOf[CT] .getOrElse(throw new RuntimeException(s"Could not get companion object for $clazz"))
【参考方案4】:
根据Miquel的回答,这里有一个获取指定类对象的伴生对象类型引用的方法:
/**
* Returns the companion object type reference for the specified class
*
* @param clazz The class whose companion is required
* @tparam CT Type of the companion object
* @return The type of the relevant companion object
*/
def companionOf[CT](clazz: Class[_]): CT =
import scala.reflect.runtime.currentMirror => cm
Try[CT]
val companionModule = cm.classSymbol(clazz).companion.asModule
cm.reflectModule(companionModule).instance.asInstanceOf[CT]
.getOrElse(throw new RuntimeException(s"Could not get companion object for $clazz"))
【讨论】:
以上是关于通过给定的泛型类型 Scala 获取类的伴随对象的主要内容,如果未能解决你的问题,请参考以下文章