2011-10-16 88 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”,是正确的吗? –