2012-08-26 23 views
8

請考慮下面的代碼:我怎樣才能得到由Scala 2.10反射引用的實際對象?

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

我可以得到Symbol指該對象,像這樣:

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

現在,有這個標誌,我怎樣才能得到實際ResponseType對象?現在

回答

13
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在一個不起眼的實現細節,我們已經(呢!)。

對於每個object Scala創建一個代表其簽名的基礎類,內部稱爲模塊類。例如,如果編譯object C,編譯器將生成C$.class。這正是模塊類。

請注意,模塊類與伴隨類不同。假設對於case class C,編譯器將生成三個符號:type C,term C和(另一個)type C,其中第一個type C代表C類(包含自動生成的副本,productPrefix,productArity等),第二個代表簽名對象C(包含自動生成的工廠,提取器等)。不會有任何名稱衝突,因爲模塊類不會直接添加到符號表中,只能通過<module>.moduleClass獲得。


所以你真正從typeOf[ResponseType.Value].asInstanceOf[TypeRef].pre.typeSymbol咒語得到的是代表一個模塊類的符號。 API中沒有任何功能可以讓您從模塊類獲取模塊符號。在編譯器內部肯定有一個,但我們決定不公開這個實現細節,因爲它很快就會改變。

要訪問源模塊,您需要訪問owner,查看其成員列表並查找與模塊類具有相同名稱的對象。這正是moduleClass.owner.typeSignature.member(moduleClass.name.toTermName)所做的。一個小問題是,如果在同一範圍內,你有一個同名的方法,那麼member將返回一個超載符號,並且你需要做一些類似於.member(...).suchThat(_.isModule)的操作。

之後,這是一塊蛋糕。


編輯。實際上,我們正在考慮引入ClassSymbol.module,否則將返回模塊類的源模塊符號和NoSymbol。很可能這會在RC1中結束。按照發行說明。

+0

我怎麼知道你會回答這個問題? ) –

+3

爲什麼需要施放?我認爲'asInstanceOf'承認失敗,並且有一個等待發生的錯誤。 –

+0

另一種表示法是:'val TypeRef(pre,_,_)= typeOf [...]; val moduleClass = pre.typeSymbol'。 –