Scala和泛型的奇怪之处

时间:2013-02-20 12:27:39

标签: scala generics

我遇到了这种类型不匹配,我不明白:

error: type mismatch;
found   : org.fluentlenium.core.domain.FluentList[_<:org.fluentlenium.core.domain.FluentWebElement]
required: org.fluentlenium.core.domain.FluentList[?0(in value $anonfun)] where type ?0(in value $anonfun) <: org.fluentlenium.core.domain.FluentWebElement
Note: org.fluentlenium.core.domain.FluentWebElement >: ?0, but Java-defined class FluentList is invariant in type E.
You may wish to investigate a wildcard type such as `_ >: ?0`. (SLS 3.2.10)

实际上,已经确定“找到”值的类型为:

org.fluentlenium.core.domain.FluentList[_<:org.fluentlenium.core.domain.FluentWebElement] =&gt;变体类型参数

我不能代表这样的情况,其中“找到”值是变体类型参数。我尝试了这个简单的代码段:

public class CarList<E extends Car> implements Collection<E> { // written in Java
   //overriden methods from Collection here
}

public class Car{} // written in Java

public Ferrari extends Car{} //written in Java

object Main extends App {  

   val carList: CarList[Car] = new CarList[Car]

   val l: CarList[Ferrari] = carList

}

编译错误发生非常相似:

error: type mismatch;
found   : app.CarList[app.Car]     //but in this case, logically it's an invariant type: Car
required: app.CarList[app.Ferrari]
Note: app.Car >: app.Ferrari, but Java-defined class CarList is invariant in type E.
You may wish to investigate a wildcard type such as `_ >: app.Ferrari`. (SLS 3.2.10)
val l: CarList[Ferrari] = carList
                                     ^

如何修改我的代码段以完全符合:

  • FluentList的错误相同的错误(在“找到”值中精确定义变量类型参数):
    found : app.CarList[_ :> app.Car]
  • 与编译器的建议相同:
    You may wish to investigate a wildcard type such as _ >:

这样我才能弄清楚问题的根源是什么?

1 个答案:

答案 0 :(得分:0)

在您的java示例中,您似乎已经颠倒了两件事。您无法将汽车列表分配给法拉利列表。

考虑到这一点,我解释了这样的片段:

class CarList[E <: Car]

class Car
class Ferrari extends Car

object Main extends App {

  val carList = new CarList[Ferrari]

  // this now throws a compiler error
  val l: CarList[Car] = carList
}

编译器错误如下:

type mismatch;
found: CarList[Ferrari] required: CarList[Car]
Note: Ferrari <: Car, but class CarList is invariant in type E.
You may wish to define E as +E instead.

所以编译器实际上帮助了我们。这个定义:

class CarList[E <: Car]

告诉编译器我们有一个扩展Car的内容列表。

但是,这并没有告诉编译器CarList[Ferrari]也扩展了CarList[Car]。为了告诉编译器,我们需要使用E进行+协变。

因此,为了解决这个错误,我们可以做两件事:

  1. CarList定义为CarList[+E],说您不关心其中的内容,但如果A延伸B,则可以考虑延长CarList[A] CarList[B]
  2. CarList定义为CarList[+E <: Car],与1相同,但对E的类型有额外的限制,因为它必须是Car
  3. This question about variance可能会提供更多信息。