1. 程式人生 > >scala flatMap為何能過濾掉Option中的None

scala flatMap為何能過濾掉Option中的None

-------------------------------------------------------------------------
*************************************************************************
-------------------------------------------------------------------------
import scala.collection.mutable._
def indexes(a: Array[String], m: Map[String,Int]) = a.flatMap(m.get(_))
def 
indexes1(a: Array[String], m: Map[String,Int]) = a.map(m.get(_)) val am = Array("Tom", "Fred", "Harry") val m1 = Map("Dick" -> 4)

呼叫這倆個方法:

val inamm=indexes(am,m1)
inamm.foreach(print(_))
println
val inamm1=indexes1(am,m1)
inamm1.foreach(print(_))

輸出結果:

3
Some(3)NoneNone

-------------------------------------------------------------------------
*************************************************************************
-------------------------------------------------------------------------

很好奇為什麼能過濾掉None,請教了scala中國群裡的kerr、林晴、wxk、小星心等人,總結如下:

(1) m.get(_)的返回型別是Option[Int],這個好理解;原始碼中Option.class中有這樣的隱式轉換:

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

toList的定義如下:
def toList: List[A] =
  if (isEmpty) List() else new ::(this.get, Nil)
所以是轉換為了List(2)或者List(),注意List(2)是單例List,即僅僅有一個元素。
-----------------------------------------
-----------------------------------------
(2)再看flatMap的原始碼(在Idea裡面,按住Ctrl,然後滑鼠點進去,即可看到呼叫的原始碼)

//這裡是TraversableLike.class中
def flatMap[B, That](f: A => GenTraversableOnce[B])(implicit bf: CanBuildFrom[Repr, B, That]): That = {
  def builder = bf(repr) // extracted to keep method size under 35 bytes, so that it can be JIT-inlined
val b = builder
  for (x <- this) b ++= f(x).seq
  b.result
}
注意程式碼實現部分主要與bf有關,在點進去看bf的實現:
-----------------------------------------
-----------------------------------------
trait CanBuildFrom[-From, -Elem, +To] {

  /** Creates a new builder on request of a collection.
   *  @param from  the collection requesting the builder to be created.
   *  @return a builder for collections of type `To` with element type `Elem`.
   *          The collections framework usually arranges things so
   *          that the created builder will build the same kind of collection
   *          as `from`.
   */
def apply(from: From): Builder[Elem, To]
顯然是呼叫了apply(from:From),點進去Builder:
-----------------------------------------
-----------------------------------------
import generic._

/** The base trait of all builders.
 *  A builder lets one construct a collection incrementally, by adding
 *  elements to the builder with `+=` and then converting to the required
 *  collection type with `result`.
 *
 *  @tparam  Elem  the type of elements that get added to the builder.
 *  @tparam  To    the type of collection that it produced.
 *
 *  @since 2.8
 */
trait Builder[-Elem, +To] extends Growable[Elem] {

  /** Adds a single element to the builder.
   *  @param elem the element to be added.
   *  @return the builder itself.
   */
從英文部分可得到下面的naive interpretation
-----------------------------------------
-----------------------------------------
implicit bf: CanBuildFrom[Repr, B, That],它這個是先讓this.asInstanceOf(Repr),然後逐個新增元素B,最後返回結果That。
即它是要求輸入資料是Repr,新增這個集合中的資料是B,這個集合的result()方法返回的是That型別.

-----------------------------------------
-----------------------------------------
(3) 正是bf++=f(x).seq,f(x)是List,List中++是可以過濾掉List()的。

至此,對題目中的問題做了一個粗略的分析,由於是初學者,以後再慢慢清晰化。

有問題請及時留言或者傳送郵件到[email protected]