Получить сопутствующий объект класса по заданному универсальному типу Scala - PullRequest
27 голосов
/ 07 февраля 2012

То, что я пытаюсь сделать, - это создать функцию, которая будет принимать универсальный класс и использовать в нем статический метод (извините за язык 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
}

Есть идеи?

Ответы [ 3 ]

24 голосов
/ 07 февраля 2012

Суть Майлза Сабина может дать вам подсказку:

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
}

Это должно быть скомпилировано с флагом -Ydependent-method-types при использовании Scala 2.9.x.

8 голосов
/ 07 февраля 2012

Вы можете использовать отражение, чтобы получить класс-компаньон и его экземпляр, но это зависит от внутренних компонентов 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))
2 голосов
/ 03 мая 2018

Я продолжаю посещать эту страницу, когда забываю, как это сделать, и ответы не являются на сто процентов удовлетворительными для меня. Вот как я делаю с отражением:

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

Возможно, вам потребуется проверить, что класс действительно имеет объект-компаньон, или companion.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}"))

}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...