Scala 中的 flatMap 函数

flatMap function in scala

在以下两个场景中,我在列表上调用了 flatMap 函数。在这两种情况下, flatMap 函数的 map 部分都返回一个具有迭代器的数组。在第一种情况下,代码出错,在第二种情况下,它产生了预期的结果。

场景 1

1
2
3
4
5
6
val x = List("abc","cde")
x flatMap ( e => e.toArray)
<console>:13: error: polymorphic expression cannot be instantiated to expected type;
 found   : [B >: Char]Array[B]
 required: scala.collection.GenTraversableOnce[?]
       x flatMap ( e => e.toArray)

场景 2

1
2
3
val x = List("abc,def")
x flatMap ( e => e.split(",") )
res1: List[String] = List(abc, def) //Result

你能帮忙解释为什么在第一种情况下,它的行为不符合预期吗?


值得牢记的是,Array 不是一个合适的 Scala 集合,因此编译器必须更加努力地首先将其转换为适合其余 Scala 集合的内容

1
2
implicitly[Array[Char] <:< GenTraversableOnce[Char]] // error (Scala 2.12)
implicitly[Array[Char] <:< IterableOnce[Char]]       // error (Scala 2.13)

因此因为 flatMap 接受一个函数

1
String => GenTraversableOnce[Char]

但我们正在传入

1
String => Array[Char]

编译器首先必须找到合适的 Array[Char]GenTraversableOnce[Char] 的隐式转换。即这应该是 wrapCharArray

1
scala.collection.immutable.List.apply[String]("abc","cde").flatMap[Char](((e: String) => scala.Predef.wrapCharArray(scala.Predef.augmentString(e).toArray[Char]((ClassTag.Char: scala.reflect.ClassTag[Char])))))

或更短

1
List("abc","cde").flatMap(e => wrapCharArray(augmentString(e).toArray))

但是由于 Jasper-M 解释的类型推断原因,编译器无法选择 wrapCharArray 转换。正如丹尼尔所说

Array tries to be a Java Array and a Scala Collection at the same
time. It mostly succeeds, but fail at both for some corner cases.

也许这是其中一种极端情况。由于这些原因,最好避免 Array 除非性能或兼容性原因要求它。然而,似乎在 Scala 2.13 中工作的另一种方法是使用 to(Collection) method

1
List("abc","cde").flatMap(_.to(Array))


我认为不同之处在于,在场景 1 中,您实际上有一个 Array[B],其中 BChar 的某个尚未确定的超类型。通常编译器会寻找到 GenTraversableOnce 的隐式转换,但是因为 B 还不知道,你会遇到类型推断问题/限制。

您可以通过填写B.

来帮助类型推断

1
List("abc","cde").flatMap(_.toArray[Char])

或者更好的是,在这种情况下您不需要 flatMap。只需调用 flatten.

1
List("abc","cde").flatten

1
2
3
4
5
scala> val x = List("abc","cde")
x: List[String] = List(abc, cde)

scala> x.flatMap[Char](_.toArray)
res0: List[Char] = List(a, b, c, c, d, e)


如错误所述,您的类型错误。

在第一种情况下,如果您应用地图而不是平面地图,您将获得 List[Array[Char]]。如果你对它应用 flatten,你会得到一个 List[Char]

在第二种情况下,如果您应用地图而不是平面地图,您将获得 List[Array[String]]。如果你对它应用 flatten,你会得到一个 List[String]

我想您需要将数组中的 String 转换为 Char,以使其工作。

我使用 Scala 2.13 并且仍然有同样的错误。