2

我正在尝试将 y 转换为可以附加到 x 的东西,其中 x 是某种序列。

scala> def foo[U <: Seq[T], T](x: U, y: T): U = x :+ y
<console>:7: error: type mismatch;
 found   : Seq[T]
 required: U
       def foo[U <: Seq[T], T](x: U, y: T): U = x :+ y
                                                  ^

我有以下解决方案:

def foo[T]( x : Seq[T], y:T) = x :+ y
def foo[T]( x : Seq[T], y:T) : Seq[T] = x :+ y
def foo[U <: Seq[T], T](x: U, y: T): U = (x :+ y).asInstanceOf[U]

但我怀疑为什么原来的那个不起作用。看起来如果我应用:+在超类中定义的运算符(在这种情况下)然后它返回超类?即 ifU是 a Vectorfoo返回Seq,所以我得到错误required "U" but found "Seq[T]"

谁能启发我为什么会看到这种行为?

4

2 回答 2

3

当遇到类型问题时,我通常采用“如果它通过编译,会发生什么”的逻辑来寻找不合理的部分。

在你的情况下,假设原来的是好的。

 def foo[U <: Seq[T], T](x: U, y: T): U = x :+ y

因为 Seq[T] 在 T 上是协变的,所以下面的情况成立。

 for type A, T, if A <: T, List[A] <: Seq[T]

然后我们可以进行如下操作:

 class Parent 
 class Child extends Parent

 // List(new Child) :+ (new Parent) => List[Parent]
val result = foo(List(new Child), new Parent)

U实际上是foo方法中的List[Child],但是当List以与其元素类型不同的类型操作时,它会尝试找到共同的父级,在这种情况下结果是用List[Parent]键入的,但是需要的类型是列表[子项]。显然,List[Parent] 不是 List[Child] 的子类型。

所以,问题是最终类型是提升的,但所需的类型是提升类型的子类型。如果你看一下 Scala SeqLike 的定义,这可能会更清楚。

trait SeqLike[+A, +Repr] extends ... {
    def :+[B >: A, That](elem: B)(...): That = {
       ...
    }
}
于 2015-07-31T07:38:10.690 回答
2

让我们简化这个例子

  class T
  class B extends T

  def bar[U <: T](x: T): U = {
    new B
  }

这不会编译,因为当你打电话

bar(new T)

你应该返回类型 T,但你试图返回类型 B。B 是 T 的子类型,但你应该完全返回 U,而不仅仅是返回 T 的子类型。

您可以通过以下方式解决您的问题

def foo[U <: Seq[T], T](x: U, y: T): Seq[T] = x :+ y

或者

def foo[B >: Seq[T], U <: Seq[T], T](x: U, y: T): B = y +: x
于 2015-07-31T07:04:15.620 回答