Scala泛型 - 为什么scala在使用类型约束时返回超类型的实例而不是子类型?

时间:2015-07-31 05:14:29

标签: scala types casting programming-languages scala-generics

我试图将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]

但我怀疑是为什么原来的那个没有用。看起来如果我应用超类中定义的运算符(在这种情况下为:+),那么它会返回超类?如果UVectorfoo会返回Seq,那么我会收到错误required "U" but found "Seq[T]"

任何人都可以告诉我为什么会出现这种行为吗?

2 个答案:

答案 0 :(得分:3)

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

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

 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 [Child]。显然,List [Parent]不是List [Child]的子类型。

因此,事情是最终类型被提升但所需类型是提升类型的子类型。 如果你看一下Scala SeqLike的定义,这可能会更清楚。

trait SeqLike[+A, +Repr] extends ... {
    def :+[B >: A, That](elem: B)(...): That = {
       ...
    }
}

答案 1 :(得分:2)

让我们简化一下这个例子

A

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

field_two

你应该返回类型T,但是你试图返回类型B.B是T的子类型,但是你应该返回ex,但不仅仅是T的子类型。

您可以通过

解决问题
A and B

  class T
  class B extends T

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