Вопрос по scala, reflection – Получить экземпляр объекта-компаньона с новым API отражения Scala

27

Можно ли с помощью нового API отражения Scala получить ссылку на объект-компаньон класса? Я думаю что-то вроде этого:

trait Base {
  def companion: MetaBase = someReflectionMagic(this).asInstanceOf[MetaBase]
}

trait MetaBase {
  // stuff
}

// ---

class Foo extends Base

object Foo extends MetaBase

assert(new Foo.companion == Foo)
Я думаю, что вы могли бы сойти с рук с чем-то вроде этогоstackoverflow.com/questions/1913092/… Noah
Я надеялся на что-то более чистое, используя новый API отражения. leedm777

Ваш Ответ

2   ответа
37

чительной степени способствовали процессу разработки рефлексии и макросов, и я очень рад быть частью нашего удивительного сообщества.

Прежде чем ответить на ваш вопрос, я бы хотел начать с заявления об отказе. В 2.10.0-M4 мы только что заложили основы API отражения Scala. В прессе по-прежнему жарко, поэтому документов очень мало, а API не совсем изобилует удобствами. Это работает, но требует тестирования и обратной связи. Конечно, возиться с API предварительной версии проблематично, но я всегда здесь, чтобы помочь.

Пока у нас есть черновик того, что в будущем станет отражением SIP:https://docs.google.com/document/d/1Z1VhhNPplbUpaZPIYdc0_EUv5RiGQ2X4oqp0i-vz1qw/edit#heading=h.pqwdkl1226tc, Вы можете прочитать это прямо сейчас или сначала просмотреть мой ответ ниже.

trait Base {
  def companion: MetaBase = {
    // runtime reflection is typically done
    // by importing things from scala.reflect.runtime package
    import scala.reflect.runtime._

    // the new Scala reflection API is mirror based
    // mirrors constitute a hierarchy of objects
    // that closely follows the hierarchy of the things they reflect
    // for example, for a class you'll have a ClassMirror
    // for a method you'll have a MethodMirror and so on
    // why go the extra mile?
    // because this provides more flexibility than traditional approaches
    // you can read more about mirror-based designs here:
    // https://dl.dropbox.com/u/10497693/Library/Computer%20Science/Metaprogramming/Reflection/mirrors.pdf
    // https://dl.dropbox.com/u/10497693/Library/Computer%20Science/Metaprogramming/Reflection/reflecting-scala.pdf

    // bottom line is that to do anything you will need a mirror
    // for example, in your case, you need a ClassMirror

    // remember I said that mirrors provide more flexibility?
    // for one, this means that mirror-based reflection facilities
    // might have multiple implementations
    // in a paper linked above, Gilad Bracha muses over a runtime
    // that loads things remotely over the network
    // in our case we might have different mirrors for JVM and CLR
    // well, anyways

    // the canonical (and the only one now) implementation of the mirror API
    // is Java-based reflection that uses out of the box classloaders
    // here's its root: https://github.com/scalamacros/kepler/blob/9f71e9f114c10b52350c6c4ec757159f06e55daa/src/reflect/scala/reflect/api/Mirrors.scala#L178
    // yeah, right, I've just linked a source file from trunk
    // we'll have Scaladocs for that soon, but for now take a look
    // this file is interfaces-only and is heavy on comments

    // to start with Java-based reflection implementation you need a classloader
    // let's grab one and instantiate the root mirror
    // btw, the same effect could be achieved by writing
    // `scala.reflect.runtime.currentMirror`
    val rootMirror = universe.runtimeMirror(getClass.getClassLoader)

    // now when we've finally entered the reflective world
    // we can get the stuff done
    // first we obtain a ClassSymbol that corresponds to the current instance
    // (ClassSymbols are to Scala the same as Classes are to Java)
    var classSymbol = rootMirror.classSymbol(getClass)

    // having a Scala reflection entity
    // we can obtain its reflection using the rootMirror
    val classMirror = rootMirror.reflectClass(classSymbol)

    // now we just traverse the conceptual hierarchy of mirrors
    // that closely follows the hierarchy of Scala reflection concepts
    // for example, a ClassMirror has a companion ModuleMirror and vice versa
    val moduleMirror = classMirror.companion.get

    // finally, we've arrived at our destination
    moduleMirror.instance.asInstanceOf[MetaBase]
  }
}

trait MetaBase {
  // stuff
}

// ---

class Foo extends Base

object Foo extends MetaBase

object Test extends App {
  assert(new Foo().companion == Foo)
}

Обновить. Пожалуйста, посмотрите также превосходную статью Даниэля Собрала:http://dcsobral.blogspot.ch/2012/07/json-serialization-with-reflection-in.html.

Как обновить этот код, чтобы он работал в финале scala 2.10.0?
смотреть наthis question также - хотя есть ответ, который кажется хорошим.
@EugeneBurmako: Потрясающий ответ. Вы должны рассмотреть возможность обновления своего ответа с информацией, предоставленной в вашей сути.
Мне нравится энтузиазм Юджина и смиренно извиняющийся тон, который он не потерял два года спустя. Жаль, что ответ не получил зеленую галочку.
5

ля Scala 2.10.

trait ReflectionSugars{
  import scala.reflect.runtime.{universe => ru}
  private lazy val universeMirror = ru.runtimeMirror(getClass.getClassLoader)

  def companionOf[T](implicit tt: ru.TypeTag[T])  = {
    val companionMirror = universeMirror.reflectModule(ru.typeOf[T].typeSymbol.companionSymbol.asModule)
    companionMirror.instance
  }

}

trait X extends ReflectionSugars{
   def companion = companionOf[X]
}

https://gist.github.com/piotrga/5928581

Надеюсь, это поможет!

Похожие вопросы