val a:设置[Fruit] =设置[Apple]()不编译,为什么?怎么修好?

时间:2014-03-14 08:36:15

标签: scala generics

val a: 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]()
                         ^

编辑:

正如Jatin的回答所指出的,这个问题已在这里得到解答:Why is Scala's immutable Set not covariant in its type?

3 个答案:

答案 0 :(得分:4)

Set的类型参数(甚至是不可变的)是不变的(主要是因为Set[A]继承自A => Boolean,这是A中的反对变体。 List的类型参数是协变的。

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

val a: Set[_ <: Fruit] = Set[Apple]()

答案 1 :(得分:2)

因为List的类型参数(声明为List[+A])是{-3}}(声明为Set[A])的共变量,所以它是不变的。

简而言之,

协方差是:将更广泛的类型转换为窄类型(例如将List[Animal转换为List[Dog] Contra-variance 正在将窄类型转换为更宽泛的类型。例如Function1[Dog, something]扩展Function1[Animal, Something]。在这里,您要将Dog(缩小)转换为Animal(更宽)

Invariance 不允许你做以上任何事情。

有几个链接可用于解释协方差和反方差:

  1. Set(@serejja提到这是评论)
  2. Why is Scala's immutable Set not covariant in its type?
  3. Why doesn't the example compile, aka how does (co-, contra-, and in-) variance work?
  4. http://blogs.atlassian.com/2013/01/covariance-and-contravariance-in-scala/

答案 2 :(得分:1)

因为List是协变的,所以ant Set是不变的。看看定义:

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

trait Set[A] extends ...