GenericTraversableTemplate ::扁平化。它有什么神奇之处?

时间:2016-07-15 17:13:32

标签: scala collections flatten

我试图了解flatten方法的神奇之处。这是一个示例表单this article

def toInt(s: String): Option[Int] = {
    try {
        Some(Integer.parseInt(s.trim))
    } catch {
        // catch Exception to catch null 's'
        case e: Exception => None
    }
}

scala> val strings = Seq("1", "2", "foo", "3", "bar")
strings: Seq[java.lang.String] = List(1, 2, foo, 3, bar)

scala> strings.map(toInt)
res0: Seq[Option[Int]] = List(Some(1), Some(2), None, Some(3), None)

scala> val flattenResult = mapResult.flatten
flattenResult: Seq[Int] = List(1, 2, 3)

哇。它看起来像是一个奇迹。 flatten方法如何知道我们不应将None添加到生成的集合中。它的实现根本不明显:

def flatten[B](implicit asTraversable: A => /*<:<!!!*/ GenTraversableOnce[B]): CC[B] = {
    val b = genericBuilder[B]
    for (xs <- sequential)
      b ++= asTraversable(xs).seq
    b.result()
  }

难道你不能解释它的意义......我的意思是它一般会做什么?也许它确实知道,None monadic值 并使用它的一些“monadic”方法。但这只是猜测。

2 个答案:

答案 0 :(得分:2)

Flatten方法隐式接收一个能够获取A(在我们的例子中为Option)并将其转换为GenTraversableOnce的方法。

Option对象中定义了一个隐式方法:

implicit def option2Iterable[A](xo: Option[A]): Iterable[A] = xo.toList

在返回Iterable之前,toList检查对象是否为空:

def toList: List[A] =
    if (isEmpty) List() else new ::(this.get, Nil)

这意味着我们将在None上应用option2Iterable时获得一个空列表。

所以这一行:

b ++= asTraversable(xs).seq

实际上,当在“无”上执行时,将空seq添加到b,或者在某些情况下,将某些值添加到“某些”的列表中。

这就是为什么你在展平输出中看不到None / Some对象,而只看到Some对象的值。

答案 1 :(得分:2)

您看到flatten可以在包含可转换为GenTraversableOnce的值的集合上调用:

def flatten[B](implicit asTraversable: A => GenTraversableOnce[B]): CC[B]

由于在Option companion object中存在隐式转换为Iterable,因此它应该有资格成为flatten - ed(Iterable是{GenTraversableOnce的子类型1}})。

它将Option转换为List,其实现很明显..

如果我错了,请纠正我,我对Scala的馆藏实施感到不知所措......