假设我有两个A和B类,其中B是A的子类型。显然,这只是更丰富的类型层次结构的一部分,但我不认为这是相关的。假设A是层次结构的根。有一个集合类C,用于跟踪A的列表。但是,我想使C通用,这样就可以创建一个只保留B并且不接受A的实例。
class A(val c: C[A]) {
c.addEntry(this)
}
class B(c: C[A]) extends A(c)
class C[T <: A]{
val entries = new ArrayBuffer[T]()
def addEntry(e: T) { entries += e }
}
object Generic {
def main(args : Array[String]) {
val c = new C[B]()
new B(c)
}
}
上面的代码显然给出了错误'类型不匹配:找到C [B],new B(c)
行需要C [A]'。
我不确定如何解决这个问题。在T中不可能使C协变(如C[+T <: A]
),因为ArrayBuffer在T中是非变量类型的。不可能使B的构造函数需要C [B],因为C不能是协变的
我在这里咆哮错误的树吗?我是一个完整的Scala新手,所以任何想法和提示可能会有所帮助。谢谢!
编辑: 基本上,我想要的是编译器同时接受
val c = new C[B]()
new B(c)
和
val c = new C[A]()
new B(c)
但拒绝
val c = new C[B]()
new A(c)
可能放松C中ArrayBuffer的输入是A而不是T,因此在addEntry方法中也是如此,如果有帮助的话。
答案 0 :(得分:1)
在T中不能使C协变(如
中是非变量类型的C[+T <: A]
),因为ArrayBuffer在T
不仅仅是因为这个原因。 addEntry
的类型足以让它不允许:
val a: A = ...
val b: B = ...
val cb: C[B] = ...
cb.addEntry(b) // works
cb.addEntry(a) // doesn't and shouldn't
答案 1 :(得分:0)
Hacky,但似乎有效:
class A(val c: C[A]) {
c.addEntry(this.asInstanceOf[c.X])
}
class B(c: C[B]) extends A(c)
class C[+T <: A] {
type X <: T
val entries = new ArrayBuffer[X]()
def addEntry(e: X) { entries += e }
}
object Generic {
def main(args : Array[String]) {
val c = new C(){ type T = B }
new B(c)
}
}
当然,我也会对一个合适的解决方案感兴趣...
答案 2 :(得分:0)
如果你想跟踪A的实例,你必须将C [A]的实例传递给B的构造函数,因为每个B也是A:
def main(args : Array[String]) {
val c = new C[A]()
new B(c)
}
如果你想跟踪Bs,那么你不能将其委托给A,因为A对B不了解。
总的来说,我觉得你的问题有点不对劲。
答案 3 :(得分:0)
让我们说这是可能的。然后你就可以做到这一点:
class A(val c: C[A]) {
c.addEntry(this)
}
class B(c: C[A]) extends A(c)
class C[+T <: A]{
val entries: ArrayBuffer[T] @uncheckedVariance = new ArrayBuffer[T]()
def addEntry(e: T @uncheckedVariance) { entries += e }
}
object Generic {
def main(args : Array[String]) {
// Everything's fine so far...
val c = new C[B]()
c.addEntry(new B(c))
// but, suddenly...
val ca: C[A] = c
ca.addEntry(new A(ca))
// a problem appears!
c.entries forall {
case thing: B => true // ok
case otherThing => false // not ok -- c now contains an A!
}
}
}
尝试运行此代码将导致类强制转换异常。
修改强>
您添加了此要求:
val c = new C[B]() new B(c)
和
val c = new C[A]() new B(c)
但拒绝
val c = new C[B]() new A(c)
但是,如果使用B
初始化C[B]
,并且B
扩展A
,那么 B
将初始化A
C[B]
,因此违反了最后一项要求。