18

我很困惑。在TraversableLike中,有一个flatMap带有签名的函数

flatMap[B](f: (A) ⇒ GenTraversableOnce[B]): Iterable[B]

但是,我可以这样使用它

scala> Iterable(1,2,3,4,5).flatMap{i=>if (i%2==0) {None} else {Some(i)}}
res1: Iterable[Int] = List(1, 3, 5)

为什么有可能?是如何Option转换成的GenTraversableOnce?好像不是子类...

4

3 回答 3

20

正如您在类图(*)中看到的那样,Option它不是 的子类GenTraversableOnce,但有一个可用于 的隐式转换Iterable,即GenTraversableOnce.

在此处输入图像描述

(*) 是的,好吧,我作弊了。Scaladoc 上还没有类图……但明天应该会出现!:-)

于 2012-07-11T21:40:33.230 回答
17

实际上默认情况下存在从 Some[X] 到 GenTraversableOnce[X] 的隐式转换。这在 REPL 中测试非常简单

scala>  implicitly[Function[Some[Int],GenTraversableOnce[Int]]]
res1: Some[Int] => scala.collection.GenTraversableOnce[Int] = <function1>

scala> implicitly[Some[Int] => GenTraversableOnce[Int]] // alternative syntax
res2: Some[Int] => scala.collection.GenTraversableOnce[Int] = <function1>

实际上这是在对象选项中定义的。内部 scala 包:

object Option {
  /** An implicit conversion that converts an option to an iterable value
   */
  implicit def option2Iterable[A](xo: Option[A]): Iterable[A] = xo.toList

  /** An Option factory which creates Some(x) if the argument is not null,
   *  and None if it is null.
   *
   *  @param  x the value
   *  @return   Some(value) if value != null, None if value == null
   */
  def apply[A](x: A): Option[A] = if (x == null) None else Some(x)

  /** An Option factory which returns `None` in a manner consistent with
   *  the collections hierarchy.
   */
  def empty[A] : Option[A] = None
}

option2Iterable 正是您正在寻找的。您还可以看到为什么在您的 REPL 中进行测试时,您会看到 GenTraversableOnce 的实现是一个列表。

如果您正在寻找无需您执行任何操作即可自动导入的隐式转换(例如您可以在 REPL 中看到的隐式转换),您必须查看:

  • Predef.scala
  • 类的伴随对象
于 2012-07-11T09:46:25.787 回答
3

似乎它确实被隐式转换为List.

scala> val l:scala.collection.GenTraversableOnce[Int] = Some(3)
l: scala.collection.GenTraversableOnce[Int] = List(3)

scala> val l:scala.collection.GenTraversableOnce[Int] = None
l: scala.collection.GenTraversableOnce[Int] = List()

个人说明:scala 魔术隐式转换有时真的很混乱。

于 2012-07-11T09:18:12.877 回答