为什么这个函数不能编译?
case class MyType(n: Int)
def intersection(s1: Set[MyType], s2: Set[_ <: MyType]) =
(s1 & s2)
我收到以下错误:
错误:类型不匹配;找到:设置[_ $ 1],其中类型_ $ 1 &lt;:需要MyType:scala.collection.GenSet [MyType]注意:_ $ 1&lt;: MyType,但特性GenSet在A类中是不变的。你可能希望 调查通配符类型,例如
_ <: MyType
。 (SLS 3.2.10) (w&amp; r)
是否有一种简单的方法可以“提升”第二个参数,而不使用asInstanceOf来键入Set [MyType]?
答案 0 :(得分:3)
这是因为Set
被定义为Set[A]
。它是 in-variant 而不是共变体。
&
定义为
def &(that: GenSet[A]): Set[A]
它期望和Set[A]
类型的参数。但是你提供的是Set[_ <: MyType]
。
Set[_ <: Mytype]
与Set[MyType]
共同变体。但正如声明所说,论证应该是变体的,即Set[MyType]
,因此错误。
PS:您可以将协方差视为从窄到宽的类型转换。例如:如果Dog
延伸Animal
而你执行Animal a = new Dog()
,则会有狗(缩小)转换为动物(更广泛)。期望它不变的类型。即如果它需要Animal
,则只能提供Animal
。另一个例子是java.util.ArrayList
,它是变体。
答案 1 :(得分:2)
Set
与其类型参数不协变。
所以一个简单的解决方案是转换为List
(协变):
def intersection(s1: Set[MyType], s2: Set[_ <: MyType]) =
s1.toList.intersect(s2.toList).toSet
答案 2 :(得分: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.apply
类型(MyType) => Boolean
可以接受为(_ <: MyType) => Boolean
。
效果与intersect
相同,因为this filter that
是intersect
的{{1}}实现方式。