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

时间:2017-01-23 16:53:20

标签: scala types functional-programming scala-collections

为什么Scala编译器不会让您flatMap Set[Set[_ <: SomeType]],但会flatMap 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)

1 个答案:

答案 0 :(得分:1)

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