2013-12-18 35 views
1

我剛剛開始嘗試使用Scala 2.10中引入的反射API,並期望下面的代碼評估爲真五次(REPL)。使用TypeTags和單例類型的Scala反射

不幸的是,只有第一個和最後一個表達式確實有效。有人可以解釋爲什麼會出現這種情況嗎?從編譯器的角度來看,所有這些類型的比較都可以,或者我錯了?

有沒有辦法讓這個(至少有一個.type比較)的工作?

import scala.reflect.runtime.universe._ 

class Test[A:TypeTag](val a:A) { 
    val value:this.type=this 
    def t1:TypeTag[Test[A]]=typeTag[Test[A]] 
    def t2:TypeTag[this.type]=typeTag[this.type] 
    def t3:TypeTag[_<:Test[A]]=typeTag[this.type] 
} 

val a:Test[String]=new Test("a") 

a.t1.tpe<:<typeOf[Test[String]] //works as expected 
a.t2.tpe<:<typeOf[Test[String]] //FAILS 
a.t3.tpe<:<typeOf[Test[String]] //FAILS 
a.t2.tpe<:<typeOf[a.type] //FAILS 
typeOf[a.type]<:<typeOf[a.type] //this works again 

使用Scala REPL 2.10.3和2.11.0-M7進行測試。

問候,

梅西

回答

1

這裏要記住的基本事實是,單類型與對象(具體情況)有關。相反,它們與標識符相關聯。

這意味着單個對象可以具有多個單身類型,具體取決於它分配的標識符。例如:

class C { 
    val self = this 
    val thistpe = typeOf[this.type] 
    type T1 = this.type 
    type T2 = self.type 
} 

val c1 = new C 
val c2 = c1 
val c3: c1.type = c1 

val tpe1 = typeOf[c1.type] 
val tpe2 = typeOf[c2.type] 
val tpe3 = typeOf[c3.type] 
val tpe4 = typeOf[c1.T1] 
val tpe5 = typeOf[c1.T2] 
val tpe6 = c1.thistpe 

在上面的代碼段中,tpe1tpe3tpe4將將被識別爲相同的類型,但其他的則不會。

在你的情況,你可以嘗試這樣的事情,而不是:

class C { 
    def thisTpe(implicit tag: TypeTag[this.type]) = tag.tpe 
} 

val c = new C 
c.thisTpe =:= typeOf[c.type] // yields true 
+0

但是,你的例子也是「靜態失敗」(val a:c2.type = c1)的區別嗎? 不幸的是,您的解決方案並非我所尋找的,因爲這正是我想要避免的:必須從外部傳遞類型信息。目標是一種「內在化」的類,即它帶有它自己的類型信息)。 – messi

+0

@messi是的,抱歉,我沒有聽清你問題中的所有問題。但我認爲事實仍然是一個對象不能攜帶_singleton_類型的信息,因爲它取決於使用該對象的上下文。 – ghik

2

你的類不知道它的類型參數,顯然。這可能是一個錯誤,你的t2方法不起作用。

細則中指出

一個單P型.TYPE符合路徑p的類型。

在這裏,這仍然是真實的,就目前來說,測試只是一個Test[A]。但是由於A的標籤可用,你會認爲它會使用它。

scala> typeTag[a.type].tpe 
res8: reflect.runtime.universe.Type = a.type 

scala> typeTag[a.type].tpe.widen 
res9: reflect.runtime.universe.Type = Test[String] 

scala> typeTag[a.type].tpe.widen <:< typeOf[Test[String]] 
res10: Boolean = true 

scala> typeTag[a.type].tpe <:< typeOf[Test[String]] 
res11: Boolean = true 

scala> a.t2.tpe 
res12: reflect.runtime.universe.Type = Test.this.type 

scala> a.t2.tpe.widen 
res13: reflect.runtime.universe.Type = Test[A]