Опция GenTraversableOnce?

Я смущен. В 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? Это не похоже на подкласс...

Ответы

Ответ 1

Фактически есть неявное преобразование по умолчанию от 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>

И на самом деле это определено в объекте Option. Внутри пакета 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
  • Сопутствующие объекты класса

Ответ 2

Как видно из диаграммы классов (*), Option не является подклассом GenTraversableOnce, но существует неявное преобразование, доступное для Iterable, которое является GenTraversableOnce.

enter image description here

(*) Да, хорошо, я обманул. Диаграммы классов еще не доступны на Scaladoc... но они должны быть завтра!: -)

Ответ 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 магические неявные преобразования иногда действительно запутывают.