我正在尝试使用抽象类型来简化和澄清类型处理,但我一直遇到看似非感性的错误:
trait Delta[A] {
def apply(c: A)
}
abstract class ValueHolder {
type Value
type Event <: Delta[ValueHolder]
def update(next: Value): Event = new UpdateEvent(next)
// type mismatch; found : UpdateEvent[ValueHolder]
// required: ValueHolder.this.Event
}
class UpdateEvent[C <: ValueHolder](next: C#Value) extends Delta[C] {
def apply(c: C) = c.update(next)
// type mismatch; found :
// UpdateEvent.this.next.type (with underlying type C#Value)
// required: c.Value
}
Delta[C]
C <: ValueHolder
不符合Event <: Delta[ValueHolder]
?
同样,鉴于c
是C
,不是c.Value
和C#Value
?
我可以使用强制转换来删除第二个错误,但这会破坏使用类型的重点。
我试图纳入[这个相关问题] [1]中建议的答案......
class UpdateEvent[C <: ValueHolder, V <: C#Value](next: V) extends Delta[C] {
......遗憾的是,它无法解决这两个问题(虽然从update()调用时需要更多类型参数)。
帮助???
更新:不幸的是,我上面给出的示例有点过于简单了。我正在尝试将更改传播到具有相同方法签名的类(尽管可能是不同的类型参数),因此它们充当原始的“视图”。
例如,假设你可以运行它:
(ListBuffer[Int]:_).map(_.toString)
...然后每次原始时更新结果ListBuffer[String]
。 (不只是运行“地图”,一遍又一遍,原因我不能简单介绍一下。)至于这个小小的例子,其他的定义所实现的特点,这意味着我不能改变的方法签名来解决此问题。< / p>
(注意:我也无法摆脱type Event
,因为有一个变量(此处未说明)包含收到每个Event
的所有听众 - 其类型应该被细化通过子类为每个子类提供更具体的侦听器。)
反正很多时间琢磨的不是非常自明斯卡拉参考手册后(信息都在那里,但它假定你知道很多的话),我终于想通了如何限制UpdateEvent
,因此C和C#值对应:
class UpdateEvent[V, C <: ValueHolder { type Value = V }](
next: V) extends Delta[C] { ... }
这可以修复编译错误并保留现有方法。但我正在将彼得的回答(下图)标记为正确(给予他声望点),因为我非常感谢他花时间在上面。谢谢,彼得,对你最好。
答案 0 :(得分:2)
不
Delta[C]
,C <: ValueHolder
哪里符合Event <: Delta[ValueHolder]
?
我对此并不完全确定,因此请将以下内容作为理论。如果Delta[C]
的类型参数是协变的(即C <: ValueHolder
),编译器只能确保Delta[ValueHolder]
,其中Delta
是Delta[+A]
。 。但目前它是不变的,所以上述情况并非如此。编译器也不知道Delta[C]
是否是Event
:Event
是抽象类型,即稍后定义的某些类型的占位符,是Delta[ValueHolder]
的子类型。但是,它可以定义为任何这样的子类,而不仅仅是UpdateEvent
!因此,我可以定义一个ValueHolder
子类,Event
类型为OtherEvent
,因此不是UpdateEvent
。如果编译器允许这样做,则最终结果将是运行时错误。
确实如此。但请查看错误消息:同样,鉴于
c
是C
,不是c.Value
和C#Value
?
// type mismatch; found :
// UpdateEvent.this.next.type (with underlying type C#Value)
// required: c.Value
也就是说,编译器需要一种c.Value
类型,而它需要C#Value
。而C#Value
不一个c.Value
- 前者是更一般的类型!
潜在解决方案的一部分可能是使用绑定类型参数update
对C <: ValueHolder
进行参数化,然后使用C#Value
作为参数类型,而不是ValueHolder#Value
。这将消除第二个错误。第一个问题的解决方案可能是将Event
的返回类型替换为Delta[C]
。因此,以下编译:
trait Delta[A] {
def apply(c: A): Delta[A]
}
abstract class ValueHolder {
type Value
def update[C <: ValueHolder](next: C#Value): Delta[C] = new UpdateEvent(next)
}
class UpdateEvent[C <: ValueHolder](next: C#Value) extends Delta[C] {
override def apply(c: C) = c.update(next)
}
注意:
Event
实际上不再使用,因此可以完全删除Delta.apply
的返回类型定义为Delta[A]
,以符合UpdateEvent.apply
实际返回的类型A
在这里只能是不变的,因为A
现在同时代表协变(作为方法返回类型)和逆变(作为方法参数)位置在Delta
内。希望这会有所帮助 - 我不确定你想要达到的目标,所以我可能会通过这些修改扼杀你原来的想法: - )