与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])是否未触发类型推断?
非常感谢提前。
答案 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
的调用,它实际编译得很好。你可能在某处犯了另一个错误。