【问题标题】:Scala and strangeness with GenericsScala和泛型的陌生感
【发布时间】:2013-02-21 06:26:20
【问题描述】:

我遇到了这种我不理解的类型不匹配:

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[_&lt;:org.fluentlenium.core.domain.FluentWebElement] => 变体类型参数

我无法表示这样的情况,其中“找到”值是变体类型参数。我尝试了这个简单的 sn-p 代码:

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
                                     ^

如何修改我的代码 sn-p 以准确地结束:

  • FluentList 的错误类型相同(精确到“找到”值中的变体类型参数):
    found : app.CarList[_ :&gt; app.Car]
  • 来自编译器的相同建议:
    You may wish to investigate a wildcard type such as _ &gt;:

这样我就可以弄清楚问题的根源是什么?

【问题讨论】:

  • 简单地尝试过new FluentList[FluentWebElement] ?介意粘贴 FluentList 构造函数签名吗?
  • @pedrofurla 是的,当然它会解决这个问题,但我试图了解这样一个问题的真正原因:) FluentList 是用 Java 编写的,构造函数的签名是: FluentList(java.util.Collection&lt;E&gt; listFiltered)
  • 我明白了,您对类型差异的怀疑是真实的。
  • @pedrofurla 是的,确实
  • @pedrofurla 我更新了我的代码 sn-p。

标签: scala generics


【解决方案1】:

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

考虑到这一点,我这样解释 sn-p:

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 &lt;: Car],与1相同,但对E的类型有额外的限制,因为它必须是Car

This question about variance 可能会提供更多信息。

【讨论】:

  • 抱歉,我的问题不是:“如何解决?”因为我很好地掌握了协变/逆变。我的问题是:“如何修改我的代码 sn-p 以最终出现相同类型的错误?”,这意味着我想遇到一个错误通知:“found : app.CarList[_ &lt;: app.Car] // I would like to come across this line required: app.CarList[app.Ferrari] Note: app.Car &gt;: app.Ferrari, but Java-defined class CarList is invariant in type E. You may wish to investigate a wildcard type such as _ >: app.Ferrari@ 987654342@我想看到一个带有变量参数:&gt;的“找到”@
  • 你完全正确。我读错了问题。有趣的问题!
  • 没问题 :) 我花了一整天的时间来寻找解释......我看不到一个:(
  • 您可以轻松重现此问题。您可以在这里查看我之前的帖子:stackoverflow.com/questions/14970301/…。无论使用什么“Specs2”匹配器,都会发生错误;例如:browser.find(".myClass").find("#mySubElement") must_==(null)。解决它很容易,但弄清楚为什么是另一场比赛:)
  • 该死的,这带走了我晚上剩下的时间,哈哈。我也无法重现。使用此 sn-p:val x:CarList[_ &lt;: Car] = (???):CarList[_ &gt;: Car] 得到的通配符错误非常相似。以另一种方式解决_ &lt;: Car 的错误也是可行的。显然,您发现一个构造是CarList[X &lt;: Car]CarList[X &gt;: Car] 的类型。我不知道编译器的优先规则,但它显示的是最后一种类型的信息。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-06-01
  • 2021-08-25
  • 2023-03-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-05-21
相关资源
最近更新 更多