Scala val a:Set[Fruit]=Set[Apple]()不编译,为什么?怎么能修好呢?

Scala val a:Set[Fruit]=Set[Apple]()不编译,为什么?怎么能修好呢?,scala,generics,Scala,Generics,行vala:Set[Fruit]=Set[Apple]没有编译,为什么 如何解决这个问题 package sandbox.stackOverFlow class Fruit class Apple extends Fruit class Banana extends Fruit class Why{ val a:Set[Fruit]=Set[Apple]() // Does not compile, why ? val b:List[Fruit]=List[Apple]() //

vala:Set[Fruit]=Set[Apple]
没有编译,为什么

如何解决这个问题

package sandbox.stackOverFlow

class Fruit 
class Apple extends Fruit
class Banana extends Fruit

class Why{
  val a:Set[Fruit]=Set[Apple]() // Does not compile, why ?
  val b:List[Fruit]=List[Apple]() // Does compile.
}
生成编译错误:

type mismatch;
 found   : scala.collection.immutable.Set[sandbox.stackOverFlow.Apple]
 required: Set[sandbox.stackOverFlow.Fruit]
Note: sandbox.stackOverFlow.Apple <: sandbox.stackOverFlow.Fruit, but trait Set is invariant in type A.
You may wish to investigate a wildcard type such as `_ <: sandbox.stackOverFlow.Fruit`. (SLS 3.2.10)
  val a:Set[Fruit]=Set[Apple]()
                         ^
类型不匹配;
找到:scala.collection.immutable.Set[sandbox.stackOverFlow.Apple]
必需:设置[沙箱.堆垛溢出.水果]

注意:sandbox.stackOverFlow.AppleSet
(甚至不可变)的类型参数是不变的(主要是因为
Set[A]
继承自
A=>Boolean
,这在
A
中是反变的)。
List
的类型参数是协变的


至于如何解决这个问题,编译器提供了一个潜在的解决方案:使用通配符,例如

val a: Set[_ <: Fruit] = Set[Apple]()
vala:Set[\up>,因为(声明为
List[+a]
)的类型参数是共变的,而对于(声明为
Set[a]
)它是不变的

总之,

协方差是:将较宽的类型转换为较窄的类型(例如将
List[Animal
转换为
List[Dog]
)。 相反,将狭义类型转换为广义类型。例如
Function1[Dog,something]
扩展
Function1[Animal,something]
。在这里,您将
Dog
(狭义)转换为
Animal
(广义)

不变性并不允许你做上述任何事情

有几个链接可以解释协方差和对方差:

  • (@serejja提到这是评论)

  • 这是因为
    List
    s是协变的,ant
    Set
    s是不变的

    sealed abstract class List[+A] extends...
    
    trait Set[A] extends ...
    

    是的,但这有什么意义呢?@jhegedus请阅读此文,至于如何修复此问题,编译器提供了一个潜在的解决方案:使用通配符,例如
    val a:Set[\u Regis你能不能把这个作为一个答案,它解决了使用存在类型修复它的问题。我刚刚编辑了Jean-Philippe Pellet的答案,包括这个“修复”,我希望他不会介意