概要
Seq[Option[T]].flatten はできるが、Seq[Either[A, B]].flatten とすることはできない。
flatten メソッドは、以下のように入れ子になったコレクションや Option、Try などを平滑化することができる。
また、Option を Seq で包んだ Seq[Option[T]] は flatten によって平滑化できる。
その逆 Option[Seq[T]] はできない。
なお、Either や Try を Seq で包んだ Seq[Either[A, B]] や Seq[Try[T]] は flatten によって平滑化できない。
理由
Seq[Option[T]].flatten ができる理由は、flatten の定義にある。
結論から述べると、Seq.flatten メソッドは、TraversableOnce への暗黙的な型変換が定義されていれば実行することができる。
すなわち、Option[T] には TraversableOnce への暗黙の型変換が定義されているが、Try[T] と Either[A, B] には定義されていない。
Seq.flatten の定義
では、Seq.flatten の定義を見てみよう。このメソッドは、GenericTraversableTemplate で定義されている。
genericBuilder、sequential はそれぞれ以下のように定義されている。
genericBuilder は Seq を生成するビルダーである。
sequential は呼び出し元の Seq である。
asTraversable は、コレクションの要素 (型 A) を平滑化された要素のコレクション (型 GenTraversableOnce[B]) に変換する暗黙的な関数である。
この asTraversable が option2Iterable にあたる暗黙の型変換である。
Seq[Option[T]].flatten について
ここで、Seq(Some(1), None, Some(2)).flatten
をその定義と型を照らし合わせてみよう。
まず、呼び出し元が Seq[Option[Int]] であることから、型 A は Option[Int]、型 B は Int、型 CC は Seq である。
asTraversable は、Option[Int] を GenTraversableOnce[Int] に変換する関数である。これは option2Iterable: Option[Int] -> Iterable[A]
である。
for (xs <- sequential)
によって Seq の各要素 xs: Option[Int]
に対して処理がなされる。
asTraversable(xs).seq
は Option[Int] を Iterable[Int] に変換する。それをビルダーに追加する。
このビルダー genericBuilder[Int]
は Seq を生成するので、結果として得られるのは Seq[Int]
である。
まとめ
- Seq[Option[T]].flatten によって、Seq[T] を得ることができる。
- その理由は、Option に Iterable への暗黙の型変換が定義されているからである。
- Try や Either には、TraversableOnce への暗黙の型変換が定義されていない。そのため、Seq.flatten を用いることができない。