了解 List 中的 flatMap 声明
Understanding flatMap declaration in List
我刚看了 List.flatMap
声明,对此感到有点惊讶。
final override def flatMap[B, That](f: A => GenTraversableOnce[B])
(implicit bf: CanBuildFrom[List[A], B, That]): That
其中 object List
定义:
implicit def canBuildFrom[A]: CanBuildFrom[Coll, A, List[A]] =
ReusableCBF.asInstanceOf[GenericCanBuildFrom[A]]
所以,如果我们在 List
上调用 flatMap
,我们将得到 List
并且我看不到 That
类型中的任何点,如果它总是被推导为List[B]
(因为implicit
)。
So, if we invoke flatMap
on a List[A]
we will get the List[A]
and I don't
see any point in That
type if it will always be deduced to List[B]
您遗漏的一件事是 flatMap
实际上并未在 List[+A]
上定义。它继承自 TraversableLike
,这是大多数 Scalas 集合使用的特征。它们中的每一个都可以提供隐式的 CanBuildFrom
,它可以被覆盖以提供不同的结果集合。
如果你想体验一下自定义的功能 CanBuildFrom
:
scala> :pa
// Entering paste mode (ctrl-D to finish)
import scala.collection.generic.CanBuildFrom
import scala.collection.immutable._
import scala.collection.mutable
import scala.{List, Vector}
implicit val listToVectorCBF = new CanBuildFrom[List[Int], Int, Vector[Int]] {
override def apply(from: List[Int]): mutable.Builder[Int, Vector[Int]] = this.apply()
override def apply(): mutable.Builder[Int, Vector[Int]] = Vector.newBuilder
}
// Exiting paste mode, now interpreting.
scala> List(1,2,3).flatMap(List(_))
res6: Vector[Int] = Vector(1, 2, 3)
嗯... implicit CanBuildFrom
可以用来直接构建不同类型的结构而不是 List
从而节省了一个额外的步骤。让我们看看下面的例子,
val list = List(List(1, 2, 3), List(4, 5, 6))
// now if we do a flatmap withtout overriding the implicit CanBuildFrom
val newList = list.flatMap(l => l.map(i => (i,i)))
// new list will be a List[(Int, Int)]
// but what if you wanted a map
val newMap = newList.toMap
// But you actually needed to traverse the list twice in this case
// But we can avoid the second traversal if we chose to override the implicit
val newMap2 = list.flatMap(l => l.map(i => (i,i)))(collection.breakout)
我刚看了 List.flatMap
声明,对此感到有点惊讶。
final override def flatMap[B, That](f: A => GenTraversableOnce[B])
(implicit bf: CanBuildFrom[List[A], B, That]): That
其中 object List
定义:
implicit def canBuildFrom[A]: CanBuildFrom[Coll, A, List[A]] =
ReusableCBF.asInstanceOf[GenericCanBuildFrom[A]]
所以,如果我们在 List
上调用 flatMap
,我们将得到 List
并且我看不到 That
类型中的任何点,如果它总是被推导为List[B]
(因为implicit
)。
So, if we invoke
flatMap
on aList[A]
we will get theList[A]
and I don't see any point inThat
type if it will always be deduced toList[B]
您遗漏的一件事是 flatMap
实际上并未在 List[+A]
上定义。它继承自 TraversableLike
,这是大多数 Scalas 集合使用的特征。它们中的每一个都可以提供隐式的 CanBuildFrom
,它可以被覆盖以提供不同的结果集合。
如果你想体验一下自定义的功能 CanBuildFrom
:
scala> :pa
// Entering paste mode (ctrl-D to finish)
import scala.collection.generic.CanBuildFrom
import scala.collection.immutable._
import scala.collection.mutable
import scala.{List, Vector}
implicit val listToVectorCBF = new CanBuildFrom[List[Int], Int, Vector[Int]] {
override def apply(from: List[Int]): mutable.Builder[Int, Vector[Int]] = this.apply()
override def apply(): mutable.Builder[Int, Vector[Int]] = Vector.newBuilder
}
// Exiting paste mode, now interpreting.
scala> List(1,2,3).flatMap(List(_))
res6: Vector[Int] = Vector(1, 2, 3)
嗯... implicit CanBuildFrom
可以用来直接构建不同类型的结构而不是 List
从而节省了一个额外的步骤。让我们看看下面的例子,
val list = List(List(1, 2, 3), List(4, 5, 6))
// now if we do a flatmap withtout overriding the implicit CanBuildFrom
val newList = list.flatMap(l => l.map(i => (i,i)))
// new list will be a List[(Int, Int)]
// but what if you wanted a map
val newMap = newList.toMap
// But you actually needed to traverse the list twice in this case
// But we can avoid the second traversal if we chose to override the implicit
val newMap2 = list.flatMap(l => l.map(i => (i,i)))(collection.breakout)