map函数,隐式参数CanBuildFrom的细节

http://hongjiang.info/scala-canbuildfrom-detail/

 

在twitter上看到过的:http://www.dotkam.com/2012/05/08/scala-fun-with-canbuildfrom/
《快学Scala》这本书的p333页有对CanBuildFrom这个隐式参数的解读。

1

2

3

4

5

6

def map[B, That](f: A => B)(implicit bf: CanBuildFrom[Repr, B, That]): That = {

    val b = bf(repr)

    b.sizeHint(this)

    for (x <- this) b += f(x)

    b.result

}

先要弄清楚Repr这个类型参数的含义:意思是“展现类型”?
还有Builder这个trait,里面定义了+=和result两个方法。

//2013.2.19 补充,从下面这个例子分析

1

"abc".map(_+1)

1

$ scala -Xprint:typer -e "\"abc\".map(_+1)"

 

这句表达式被翻译为StringOps.map(...) ,除了显式传入的 Char => Int 的函数,后边还有个隐式的参数:(scala.this.Predef.fallbackStringCanBuildFrom[Int])

看了一下 Predef里面,没有找到 fallbackStringCanBuildFrom ,倒是发现了
DummyImplicit 这个类,注释里有提到: @see scala.Array$, method `fallbackCanBuildFrom`
Array的伴生对象确实继承了 FallbackArrayBuilding这个类,它里面有个隐式转换方法:

1

2

3

4

5

implicit def fallbackCanBuildFrom[T](implicit m: DummyImplicit): CanBuildFrom[Array[_], T, ArraySeq[T]] =

    new CanBuildFrom[Array[_], T, ArraySeq[T]] {

    def apply(from: Array[_]) = ArraySeq.newBuilder[T]

    def apply() = ArraySeq.newBuilder[T]

}

// 继续,通过断点跟踪了一下,是在 LowPriorityImplicits 这个class里定义了一些隐式转换函数,跟上面的无关。

1

2

3

4

5

implicit def fallbackStringCanBuildFrom[T]: CanBuildFrom[String, T, immutable.IndexedSeq[T]] =

    new CanBuildFrom[String, T, immutable.IndexedSeq[T]] {

    def apply(from: String) = immutable.IndexedSeq.newBuilder[T]

    def apply() = immutable.IndexedSeq.newBuilder[T]

}

见下图:

06142757_6Tuo.jpg

而map方法是在 TraversableLike 这个trait里定义的:
06142800_8clL.jpg

把断点设置在上面的 val b = bf(repr) 这一行,先看看repr这个变量在TraversableLike里的定义,是一个函数,返回自身对象,造型为Repr类型。

/** The collection of type $coll underlying this `TraversableLike` object.  
*  By default this is implemented as the `TraversableLike` object itself,  
*  but this can be overridden.  
*/
def repr: Repr = this.asInstanceOf[Repr]

对于String来说,这个repr就是自身,bf(repr) 调用 CanBuildFrom.apply 方法,而fallbackStringCanBuildFrom提供的builder是
Builder[A,IndexedSeq[A]] 类型,它的实现实际是 VectorBuilder,见 IndexedSeq类的伴生对象。

每个集合都在其伴生对象里提供了一个隐式的CanBuildFrom对象。

builder创建好了目标类型的容器后,开始迭代当前容器执行f函数转换,并将结果填入目标容器。

for(x <- this) b+= f(x)

这个for表达式转化为 StringOps.foreach(f:A=>B),实际调用的是 IndexedSeqOptimized.foreach(f:A=>B)
里的逻辑,这个 foreach(func) 是override了 IterableLike 里的foreach方法。

VectorBuilder的result返回的是Vector类型,它也混入了IndexedSeq特质

scala> "abc".map(_+1)
res0: scala.collection.immutable.IndexedSeq[Int] = Vector(98, 99, 100)

整个来龙去脉弄清楚了。另外,Vector是树形数组,效率比较高。

转载于:https://my.oschina.net/u/2963604/blog/1841432

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值