10

このコードを検討してください:

object ResponseType extends Enumeration {
  val Listing, Album = Value
}

Symbol次のように、このオブジェクトへの参照を取得できます。

import reflect.runtime.universe._
val s = typeOf[ResponseType.Value].asInstanceOf[TypeRef].pre.typeSymbol

さて、このシンボルを持って、どうすれば実際のResponseTypeオブジェクトを取得できますか?

4

1 に答える 1

15
scala> val moduleClass = typeOf[ResponseType.Value].asInstanceOf[TypeRef].pre.typeSymbol
moduleClass: reflect.runtime.universe.Symbol = object ResponseType

scala> val module = moduleClass.owner.typeSignature.member(moduleClass.name.toTermName)
module: reflect.runtime.universe.Symbol = object ResponseType

scala> reflect.runtime.currentMirror.reflectModule(module.asModule).instance
res9: Any = ResponseType

ここで、いくつかの説明が必要です。これは、公開 API で (まだ!) 抽象化できていない非常にあいまいな実装の詳細であるためです。

For every Scala は、内部的にmodule classobjectと呼ばれる、その署名を表す基礎となるクラスを作成します。たとえば、コンパイラをコンパイルすると、 . それがまさにモジュールクラスです。object CC$.class

モジュール クラスはコンパニオン クラスとは異なることに注意してください。の場合、コンパイラは,と (別の) のcase class C3 つのシンボルを生成します。最初のシンボルはクラス C (自動生成されたコピー、productPrefix、productArity などを含む) を表し、2 番目のシンボルはオブジェクト C の署名 (含む) を表します。自動生成されたファクトリ、エクストラクタなど)。モジュール クラスはシンボル テーブルに直接追加されず、 を通じてのみ使用できるため、名前の衝突はありません。type Cterm Ctype Ctype Ctype C<module>.moduleClass


したがって、呪文から実際に得られるtypeOf[ResponseType.Value].asInstanceOf[TypeRef].pre.typeSymbolのは、モジュール クラスを表すシンボルです。API には、モジュール クラスからモジュール シンボルを取得する関数はありません。コンパイラの内部には確かに 1 つ存在しますが、この実装の詳細は公開しないことにしました。

ソース モジュールにアクセスするにはowner、 に移動し、そのメンバーのリストを調べて、モジュール クラスと同じ名前のオブジェクトを検索します。まさにそれmoduleClass.owner.typeSignature.member(moduleClass.name.toTermName)です。マイナーな注意点の 1 つは、同じスコープ内に同じ名前のメソッドがある場合member、オーバーロードされたシンボルが返されるため、.member(...).suchThat(_.isModule).

その後は簡単です。


編集。ClassSymbol.module実際には、モジュール クラスの場合はソース モジュール シンボルを返し、それ以外の場合は NoSymbol を返すように導入することを考えています。おそらくこれは RC1 で終わるでしょう。リリースノートに従ってください。

于 2012-08-26T10:15:56.730 に答える