通过给定的泛型类型 Scala 获取类的伴生对象

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/9172775/
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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-22 03:52:25  来源:igfitidea点击:

Get companion object of class by given generic type Scala

classscalaobjecttypesimplicit

提问by Wojtek Erbetowski

What I am trying to do is to make a function that would take a generic class and use a static method in it (sorry for Java language, I mean method of its companion object).

我想要做的是创建一个函数,该函数将采用泛型类并在其中使用静态方法(对不起,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
}

Any ideas?

有任何想法吗?

采纳答案by Miquel

I keep hitting this page when I forget how to do this and the answers are not hundred percent satisfactory for me. Here is how I do with reflection:

当我忘记如何执行此操作时,我会一直点击此页面,并且答案对我来说并不是百分百满意。这是我如何处理反射:

val thisClassCompanion = m.reflect(this).symbol.companion.asModule
val structural = m.reflectModule(thisClassCompanion)
                  .instance.asInstanceOf[{def doSth: Unit}]

You might need to verify that the class actually has a companion object or companion.asModule will throw a reflection exception is not a module

您可能需要验证该类是否确实有一个伴生对象或伴生对象。asModule 将抛出一个反射异常不是模块

Updated: added another example for clarity:

更新:为了清楚起见,添加了另一个示例:

    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}"))

}

回答by Eugene Yokota

A gist by Miles Sabinmay give you a hint:

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
}

This should be compiled with the -Ydependent-method-typesflag if using Scala 2.9.x.

-Ydependent-method-types如果使用 Scala 2.9.x,这应该用标志编译。

回答by MxFr

You could use reflection to get the companion class and its instance, but that relies on Scala internals that might change in some far(?) future. And there is no type safety as you get an AnyRef. But there is no need to add any implicits to your classes and objects.

您可以使用反射来获取伴随类及其实例,但这依赖于 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].collect{case a : A.type  => a(1)}
// res1: Option[A] = Some(A(1))