2013-04-03 79 views
2

約反射簡單的問題在斯卡拉:枚舉子類的字段斯卡拉

  • 我如何寫一個方法fields返回一個特定類型的所有領域,即使在子類?
  • 即使是正確的做法嗎?如果不是,你會怎麼做?

例子:

class Top { def fields = ... } 
class A extends Top { 
    val f1 = Field(...) 
    val f2 = Field(...) 
} 

(new A).fields // List(f1, f2) 
+0

看到這裏的一些例子:http://stackoverflow.com/questions/1898932/case-classes-vs-enumerations-in-scala – sschaef

+0

嗯,我接受的答案實際上回答我的問題更好,但感謝您的鏈接;) –

回答

4

所以,在我的試驗和錯誤,我發現真正的運行時類型反射是困難的,因爲Scala的在編譯時嵌入類型信息的絕招,當你請求隱式TypeTag。我發現的是,如果你想反思一個對象的類型,該對象的類型必須在編譯時可用。 (這可能反映了我的知識限制,而不是Scala反射的限制,但是我已經嘗試過,但迄今未能反映在編譯時無法捕獲的運行時類型。)

因此,這裏最接近於什麼你想,我知道該怎麼做:

scala> import scala.reflect.runtime.universe._; 
import scala.reflect.runtime.universe._ 

scala> class Base[T <: Base[T] : TypeTag] { 
    | def stringVals = typeOf[T].members.filter(_.isTerm).map(_.asTerm).filter(_.isVal).filter(_.typeSignature <:< typeOf[String]) 
    | } 
defined class Base 

scala> class Derived extends Base[Derived] { 
    | val f1 = "Bye"; 
    | val f2 = 27; 
    | val f3 = "Sad."; 
    | } 
defined class Derived 

scala> (new Derived).stringVals 
res0: Iterable[reflect.runtime.universe.TermSymbol] = List(value f3, value f1) 

注意,我必須明確地命名自己的類型時,我伸出基地,所以在編譯時,適當TypeTag可以嵌入(作爲隱入我的構造函數)。我只是不知道這個方法。

vals以TermSymbols列表的形式返回此處。我不確定你想要什麼;如果您只想要String val名稱,請將「.map(_.name.toString.trim)」添加到stringVals函數的末尾。 (我發現修剪的重要性在實踐中很重要,但是我敢打賭,隨着反射庫的敲定和演變將變得多餘。)

祝你好運!

+0

很好的答案,+1的實際例子!我首先想到你可以使用'typeOf [this.type]'來引用子類的類型,但它似乎總是指'Base' ... –