为什么当元素是通配符时你不能 flatMap a Set 但你可以 flatMap a Seq?

Why can you not flatMap a Set when the elements are wildcarded but you can flatMap a Seq?

为什么 Scala 编译器不让你 flatMap a Set[Set[_ <: SomeType]] 但会让你 flatMap a Seq[Seq[_ <: SomeType]]?此行为在下面的 Scala REPL 日志中进行了演示。

scala> class A
defined class A

scala> case class B extends A
defined class B


// If inner collection is of type Set[B] it works
scala> val x = Set(Set(B(), B()), Set(B(), B()))
x: scala.collection.immutable.Set[scala.collection.immutable.Set[B]] = Set(Set(B@6be2b567, B@169d1f92), Set(B@7fcbc336, B@1fe7fa16))

scala> x flatMap { el => el }
res8: scala.collection.immutable.Set[B] = Set(B@6be2b567, B@169d1f92, B@7fcbc336, B@1fe7fa16)


// If inner collection of type Set[_ <: A] it doesn't work
scala> val x: Set[Set[_ <: A]] = Set(Set(B(), B()), Set(B(), B()))
x: Set[Set[_ <: A]] = Set(Set(B@3751baf6, B@27e656e6), Set(B@3cfab56d, B@6b6fde93))

scala> x flatMap { el => el }
<console>:15: error: no type parameters for method flatMap: (f: Set[_ <: A] => scala.collection.GenTraversableOnce[B])(implicit bf: scala.collection.generic.CanBuildFrom[scala.collection.immutable.Set[Set[_ <: A]],B,That])That exist so that it can be applied to arguments (Set[_ <: A] => scala.collection.immutable.Set[_ <: A])
 --- because ---
argument expression's type is not compatible with formal parameter type;
 found   : Set[_ <: A] => scala.collection.immutable.Set[_ <: A]
 required: Set[_ <: A] => scala.collection.GenTraversableOnce[?B]
       x flatMap { el => el }
         ^
<console>:15: error: type mismatch;
 found   : Set[_ <: A] => scala.collection.immutable.Set[_ <: A]
 required: Set[_ <: A] => scala.collection.GenTraversableOnce[B]
       x flatMap { el => el }
                        ^


// Try the same with Seq
scala> val x = Seq(Seq(B(), B()), Seq(B(), B()))
x: Seq[Seq[B]] = List(List(B@53cba89f, B@66ad7167), List(B@14aa2123, B@7def62d0))

// Works with inner of Seq[B]
scala> x flatMap { el => el }
res10: Seq[B] = List(B@53cba89f, B@66ad7167, B@14aa2123, B@7def62d0)

scala> val x: Seq[Seq[_ <: A]] = Seq(Seq(B(), B()), Seq(B(), B()))
x: Seq[Seq[_ <: A]] = List(List(B@7a9e44ff, B@1f8e1096), List(B@13a35d3b, B@1cd93693))

// Works with inner of Seq[_ <: A]
scala> x flatMap { el => el }
res11: Seq[A] = List(B@7a9e44ff, B@1f8e1096, B@13a35d3b, B@1cd93693)


// If inner collection of type Set[_ <: A] it works if we convert to Seq and back to Set again
scala> val x: Set[Set[_ <: A]] = Set(Set(B(), B()), Set(B(), B()))
x: Set[Set[_ <: A]] = Set(Set(B@3751baf6, B@27e656e6), Set(B@3cfab56d, B@6b6fde93))

scala> x.toSeq flatMap { elem => elem.toSeq } toSet
res16: scala.collection.immutable.Set[A] = Set(B@6ab56a77, B@216a3aba, B@9760f17, B@13cfa1ec)

列表是协变的,但集合是不变的。这意味着虽然 B 是 A 的子类型,但 Set[B] 不是 Set[A]

的子类型