1

我试图使用抽象类型来简化和澄清类型处理,但我不断遇到这些看似无意义的错误:

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
}
  1. Delta[C],在哪里C <: ValueHolder,因此符合Event <: Delta[ValueHolder]

  2. 同样,鉴于这c是 a C,不是c.ValueaC#Value吗?

我可以使用强制转换来消除第二个错误,但这违背了使用类型的意义。

我试图将[这个相关问题] [1]中建议的答案纳入...

class UpdateEvent[C <: ValueHolder, V <: C#Value](next: V) extends Delta[C] {

...遗憾的是,这并不能缓解这两个问题(尽管从 update() 调用时它需要更多的类型参数)。

帮助???


更新:不幸的是,我上面给出的例子有点过于简单化了。我正在尝试将更改传播到具有相同方法签名的类(尽管可能是不同的类型参数),因此它们充当原始的“视图”。

例如,假设您可以运行以下命令:

(ListBuffer[Int]:_).map(_.toString)

...然后ListBuffer[String]每次原始更新时都会更新结果。(不只是一遍又一遍地运行“map”,原因我无法简要解释。)与这个小例子一样,其他人定义了正在实现的特征,这意味着我无法更改方法签名来解决问题。

(注意:我也无法摆脱,type Event因为有一个变量(此处未说明)包含接收每个的所有侦听Event器——并且其类型应由子类细化以允许每个侦听器的更具体类型。)

无论如何,在思考了不是很解释性的 Scala 参考手册(信息都在那里,但假设你已经知道很多)之后,我终于想出了如何进行约束UpdateEvent以使 C 和 C#Value 对应:

class UpdateEvent[V, C <: ValueHolder { type Value = V }](
  next: V) extends Delta[C] { ... }

这修复了编译错误并保留了现有方法。但我将彼得的答案(如下)标记为正确(给他声誉积分),因为我非常感谢他花时间在这上面。谢谢,彼得,祝你好运。

4

1 回答 1

2

Delta[C],在哪里C <: ValueHolder,因此符合Event <: Delta[ValueHolder]

我对此并不完全确定,因此将以下内容作为理论。如果 的类型参数是协变的(即 ),编译器只能确保Delta[C], where C <: ValueHolder, is-a 。但目前它是不变的,所以上面的说法不正确。编译器也不知道 a 是否是:是抽象类型,即稍后定义的某个类型的占位符,它将是 的子类型。但是,它可以定义为任何这样的子类,而不仅仅是!所以我可以定义一个类型为的子类,因此它不是. 如果编译器允许这样做,最终结果将是运行时错误。Delta[ValueHolder]DeltaDelta[+A]Delta[C]EventEventDelta[ValueHolder]UpdateEventValueHolderEventOtherEventUpdateEvent

同样,鉴于这c是 a C,不是c.ValueaC#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使用绑定类型 parameter进行参数化C <: ValueHolder,然后C#Value用作参数类型,而不是ValueHolder#Value. 这将消除第二个错误。第一个问题的解决方案可能是将返回类型替换为Eventwith 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.applyas的返回类型Delta[A],以符合实际返回的类型UpdateEvent.apply
  • 因此,类型参数A在这里只能是不变的,因为A现在在Delta.

希望这会有所帮助-我不确定您要达到的目标,因此我可能通过这些修改扼杀了您的原始想法:-)

于 2013-01-22T15:25:24.047 回答