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?

26
demandé sur Malvolio 2012-02-07 12:00:38

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

}
1
répondu Miquel 2018-05-09 18:35:01

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.

21
répondu Tomasz Nurkiewicz 2012-02-07 12:42:48

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))
8
répondu MxFr 2012-02-07 10:41:06