双向关联中的泛型
假设我有两个类 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)
}
}
上面的代码显然在 new B(c)
行上给出了错误“类型不匹配:找到 C[B],需要 C[A]”。
我不知道如何解决这个问题。不可能使 C 在 T 中协变(如 C[+T <: A]),因为 ArrayBuffer 在 T 中是非变体类型。不可能使 B 的构造函数需要 a 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 方法中也是如此,如果这有帮助的话。
Let's say I have two classes A and B, with B a subtype of A. This is only part of a richer type hierarchy, obviously, but I don't think that's relevant. Assume A is the root of the hierarchy. There is a collection class C that keeps track of a list of A's. However, I want to make C generic, so that it is possible to make an instance that only keeps B's and won't accept A's.
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)
}
}
The code above obviously give the error 'type mismatch: found C[B], required C[A]' on the new B(c)
line.
I'm not sure how this can be fixed. It's not possible to make C covariant in T (like C[+T <: A]
) because the ArrayBuffer is non-variantly typed in T. It's not possible to make the constructor of B require a C[B] because C can't be covariant.
Am I barking up the wrong tree here? I'm a complete Scala newbie, so any ideas and tips might be helpful. Thank you!
EDIT:
Basically, what I'd like to have is that the compiler accepts both
val c = new C[B]()
new B(c)
and
val c = new C[A]()
new B(c)
but would reject
val c = new C[B]()
new A(c)
It's probably possible to relax the typing of the ArrayBuffer in C to be A instead of T, and thus in the addEntry method as well, if that helps.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
如果你想跟踪 A 的实例,则必须将 C[A] 的实例传递给 B 的构造函数,因为每个 B 也是 A:
但是,如果你想跟踪 B,那么你可以'不要将其委托给 A,因为 A 对 B 一无所知。
总的来说,我感觉你的问题有点不适。
If you want to keep track of the instances of A, you have to pass an instance of C[A] to the constructor of B since every B is also an A:
If however you want to keep track of the Bs then you can't delegate this down to A since A doesn't know anything about B.
Overall, I have the feeling your problem is somewhat ill posed.
假设这是可能的。然后您就可以执行以下操作:
尝试运行此代码将导致类转换异常。
编辑
您添加了此要求:
但是,如果
B
使用C[B]
初始化,并且考虑到B
扩展A
,那么B
将使用C[B]
初始化A
,从而违反了最后一个要求。Let's say it was possible. Then you'd be able to do this:
Trying to run this code will result in a class cast exception.
Edit
You added this requirement:
However, if
B
is initialized withC[B]
, and given thatB
extendsA
, thenB
will initializeA
withC[B]
, thereby violating the last requirement.不仅因为这个。
addEntry
的类型足以禁止它:Not only because of this. The type of
addEntry
is enough to disallow it:Hacky,但似乎有效:
当然我也对适当的解决方案感兴趣......
Hacky, but seems to work:
Of course I would be interested in a proper solution as well...