2011-10-16 131 views
2

我有以下涉及類型參數和類型成員嵌套結構:從類型參數和類型成員聚集類型信息

trait B 

trait B1 extends B 

trait U { 
    type _B <: B 
} 

type U1 = U { 
    type _B = B1 
} 

class Q[_U <: U] { 
    override def toString() : String = { 
    // print out type information on B here... 
    } 
} 

def test() { 
    val q = new Q[U1]() 
    println(q.toString()) 
} 

這似乎是不可能的我收集,因爲這樣U1在運行時B上的類型信息被指定。

我錯了嗎?如果不是的話,是否有一個解決方案,在設置上有微小的變化?

感謝來自Kipton巴羅斯的答案,我想出了以下設置:

trait B 

trait B1 extends B 
trait B2 extends B 

trait U { 
    type _B <: B 
    implicit val mfB : Manifest[_B] 
} 

class U1 extends U { 
    type _B = B1 
    val mfB : Manifest[_B] = implicitly 
} 

class U2 extends U { 
    type _B = B2 
    val mfB : Manifest[_B] = implicitly 
} 

class Q[_U <: U](u : _U) { 
    override def toString() : String = { 
    "B: " + u.mfB.erasure.getName() 
    } 
} 

def test() { 
    println(new Q(new U1) toString) 
    println(new Q(new U2) toString) 
} 

這種方法唯一的缺點就是需要U.

的實例

回答

0

我會想到使用型號改進Manifest的組合。前者允許將抽象類型_B表示爲類型參數B,後者指示Scala編譯器將B編輯:來自調用上下文的靜態類型)類型作爲運行時對象。這是我的嘗試,

trait B 
trait B1 extends B 
trait B2 extends B 
trait U { type _B <: B } 
class U1 extends U { type _B = B1 } 

class Q[B: Manifest, _U <: U { type _B = B}](u: U) { 
    override def toString() : String = { 
    implicitly[Manifest[B]].toString // Manifest[B] was an implicit parameter to Q 
    } 
} 

// Four tests: 
println(new Q[B1, U1](new U1) toString)  // (1) prints "$line1.$read$$iw$$iw$B1" 
// println(new Q[B2, U1](new U1) toString)  // (2) correctly fails to compile 
// println(new Q[Nothing, U1](new U1) toString)// (3) correctly fails to compile 
println(new Q(new U1) toString)    // (4) prints "Nothing" (why not B1?) 

它在第一種情況下工作,其中給出顯式類型參數。第二種情況正確無法編譯,因爲U1包含B1類型,而不是B2類型。對於第三種情況也是如此。但出於某種原因,即使編譯器似乎推斷出類型B1,Scala編譯器在第四種情況下也會生成不正確的清單。我不知道這是否是一個錯誤,但這對我來說確實令人驚訝。 任何人都可以解釋爲什麼case(4)不打印B1的Manifest?

2

只是爲了清除一個誤解:Manifest不攜帶類型參數的運行時類型。它從調用站點的上下文中攜帶需要清單的方法或構造函數調用的靜態類型。

scala> def foo[A: Manifest](a: A) = (manifest[A].erasure, a.asInstanceOf[AnyRef].getClass) 
foo: [A](a: A)(implicit evidence$1: Manifest[A])(java.lang.Class[_], java.lang.Class[_]) 

scala> foo("") 
res1: (java.lang.Class[_], java.lang.Class[_]) = (class java.lang.String,class java.lang.String) 

scala> foo[AnyRef]("") 
res2: (java.lang.Class[_], java.lang.Class[_]) = (class java.lang.Object,class java.lang.String) 

scala> val a: Any = "" 
a: Any = "" 

scala> foo(a) 
res3: (java.lang.Class[_], java.lang.Class[_]) = (class java.lang.Object,class java.lang.String) 
+0

謝謝,我更新了我的答案,以澄清你的觀點。你有沒有想過爲什麼我的例子中的case(4)會打印'Nothing'?這令我感到驚訝,因爲在呼叫站點的類型推斷確定類型參數「B」爲「B1」,是正確的嗎? –