为什么set可以分配给变量而不是参数

时间:2014-05-22 07:27:34

标签: scala

与List不可变的不一致,Set是不变函数,我有一个有趣的代码我不明白它背后的原因是什么

class Fruit
case class Apple() extends Fruit

val foo: Set[Fruit] = Set(Apple())  // Compile success but why ? Set is an invariant

def doStuff(x: Set[Fruit]) = {}
val appleSet: Set[Apple] = Set(Apple())
doStuff(appleSet) // Compile failed but why ? assign to a value is fine

该失败原因(设置[Apple])是否未触发类型推断?

非常感谢提前。

1 个答案:

答案 0 :(得分:3)

以下行确实编译正常:

val foo: Set[Fruit] = Set(Apple())

原因是推论。表达式Set(Apple())出现在期望Set[Fruit]的上下文中,因此在编译时 发现没有给Set.apply ecplicitely类型参数,它会将此类型参数推断为Fruit。所以最后就好像你有:

val foo: Set[Fruit] = Set[Fruit](Apple())

哪个是完全正确的。

现在,如果你这样做,它将无法按预期编译:

scala>val foo: Set[Fruit] = Set[Apple](Apple())
<console>:8: error: type mismatch;
found   : scala.collection.immutable.Set[Apple]
required: Set[Fruit]

甚至这个:

scala> val foo = Set(Apple())
foo: scala.collection.immutable.Set[Apple] = Set(Apple())

scala> val bar: Set[Fruit] = foo
<console>:9: error: type mismatch;
 found   : scala.collection.immutable.Set[Apple]
 required: Set[Fruit]
       val bar: Set[Fruit] = foo
                             ^

在后一种情况下,foo推断为Set[Apple]而不是Set[Fruit], 因为我们没有为foo指定任何显式类型,因此没有推理的上下文,并推断出最具体的类型(最小上限)。

至于你的例子中对doStuff的调用,它实际编译得很好。你可能在某处犯了另一个错误。