scala flatMap為何能過濾掉Option中的None
阿新 • • 發佈:2018-12-31
------------------------------------------------------------------------- ************************************************************************* ------------------------------------------------------------------------- import scala.collection.mutable._ def indexes(a: Array[String], m: Map[String,Int]) = a.flatMap(m.get(_)) defindexes1(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]