5

为什么这个函数不能编译?

case class MyType(n: Int)
def intersection(s1: Set[MyType], s2: Set[_ <: MyType]) =
  (s1 & s2)

我收到以下错误:

错误:类型不匹配;found : Set[_$1] where type _$1 <: MyType required: scala.collection.GenSet[MyType] Note: _$1 <: MyType, 但 trait GenSet 在类型 A 中是不变的。您可能希望研究通配符类型,例如作为_ <: MyType. (SLS 3.2.10) (w & r)

有没有一种简单的方法可以在不使用 asInstanceOf 的情况下将第二个参数“提升”为 Set[MyType] 类型?

4

3 回答 3

3

这是因为Set被定义为Set[A]。它是不变的而不是协变的。

&定义为

def &(that: GenSet[A]): Set[A]

它期望和类型的参数Set[A]。但是您改为提供Set[_ <: MyType].

Set[_ <: Mytype]是协变的Set[MyType]。但是正如声明所说,参数应该是不变的 ie Set[MyType],因此是错误的。

PS:您可以将协方差视为从窄到宽的类型转换。例如:如果DogextendsAnimal并且如果你这样做Animal a = new Dog(),你有一个 Dog (narrow) 转换为 Animal (broader)。上面它需要不变的类型。即如果它期望Animal,你只能提供一个Animal。另一个例子是java.util.ArrayList不变的。

于 2013-08-02T07:53:48.640 回答
2

ASet在其类型参数上不是协变的。

所以一个简单的解决方案是转换为List(这是协变的):

def intersection(s1: Set[MyType], s2: Set[_ <: MyType]) =
    s1.toList.intersect(s2.toList).toSet
于 2013-08-02T08:23:04.667 回答
2

Set是不变的,但是有一个非常简单的解决方法:

def intersection(s1: Set[MyType], s2: Set[_ <: MyType]) =
  s2 filter s1

或者,如果想要为结果类型获得更好的类型推断:

def intersection[X <: MyType](s1: Set[MyType], s2: Set[X]): Set[X] =
  s2 filter s1

这里s1用作函数。函数的参数是逆变的,因此s1.applytype(MyType) => Boolean可以作为(_ <: MyType) => Boolean.

性能与 相同intersect,实现this filter that方式也相同。intersectSet

于 2017-10-09T12:47:50.017 回答