Obtenir l'objet compagnon de la classe par type générique donné Scala
Ce que j'essaie de faire est de créer une fonction qui prendrait une classe générique et utiliserait une méthode statique (désolé pour le langage Java, je veux dire la méthode de son objet compagnon).
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
}
Des idées?
3 réponses
Je continue à frapper cette page quand j'oublie comment faire cela et les réponses ne sont pas à cent pour cent satisfaisantes pour moi. Voici comment je fais avec la réflexion:
val thisClassCompanion = m.reflect(this).symbol.companion.asModule
val structural = m.reflectModule(thisClassCompanion)
.instance.asInstanceOf[{def doSth: Unit}]
Vous devrez peut-être vérifier que la classe a réellement un objet compagnon ou un compagnon.asModule lancera une exception de réflexion n'est pas un module
Mise à jour: Ajout d'un autre exemple pour plus de clarté:
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}"))
}
Un résumé de Miles Sabin peut vous donner un indice:
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
}
Ceci doit être compilé avec l'indicateur -Ydependent-method-types
si vous utilisez Scala 2.9.X.
Vous pouvez utiliser reflection pour obtenir la classe companion et son instance, mais cela repose sur des internes Scala qui pourraient changer dans une certaine mesure(?) avenir. Et il n'y a pas de sécurité de type que vous obtenez un AnyRef. Mais il n'est pas nécessaire d'ajouter des implicits à vos classes et objets.
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))