第一次看到/:以及:\这样的代码在别人的代码里,感觉很好奇,这是什么符号呢?
点进去看到方法的签名
def /:[B](z: B)(op: (B, A) => B): B = foldLeft(z)(op)
def :\[B](z: B)(op: (A, B) => B): B = foldRight(z)(op)
OK,原来是foldLeft和foldRight的简写
foldLeft和foldRight直接翻译来向左折叠,向右折叠。
foldLeft
先来看定义:
def foldLeft[B](z: B)(op: (B, A) => B): B = {
var result = z
this.seq foreach (x => result = op(result, x))
result
}
方法接受2个参数,z和op,一个是B类型的参数,一个是返回B类型的函数。
在看到这个trait其实是TraversableOnce,可迭代的集合。
def seq: TraversableOnce[A]
比如一个val listA = List(1,2,3)
listA其实是实现了TraversableOnce这个trait的。
我们可以直接使用:
scala> listA.foldLeft(0)((sum,i)=>sum+i)
res26: Int = 6
这个里面的0其实就是z返回值是Int类型即B类型
那么可以看出op这个函数返回值也需要是Int类型
可以看出
val result = z, 这里其实就是0,x=>result=op(result, x) , sum其实也是z
其实z就是返回值,this.seq在这里就是list,对list遍历,这里执行op函数。
这里我们执行的是sum+i,就是累加了1+2+3=6
foldRight
先看下定义:
def foldRight[B](z: B)(op: (A, B) => B): B =
reversed.foldLeft(z)((x, y) => op(y, x))
这里多了一个reversed
// for internal use
protected[this] def reversed = {
var elems: List[A] = Nil
self.seq foreach (elems ::= _)
elems
}
内部使用的方法,意思就是
在list的head添加一个元素,就是在List[A]这个空列表的头部每次preappend一个元素。
如果是1,2,3那么最终就是3,2,1了,逆序,很好理解。
不过这个性能就。。。。我不敢恭维了,要逆序就要遍历一遍一个数组,然后操作再遍历一次。。。再操作。
但是如果你这样写,会发现很奇怪的结果:
scala> ((1 to 5)).foldRight(100)((sum,i)=>sum-i)
res48: Int = -97
接下来看重点了,参数顺序其实变了,我们原来的y是result
(x,y) => op(y,x)
这样写就对了:
scala> ((1 to 5)).foldRight(100)((i,sum)=>sum-i)
res49: Int = 85
总结一下,foldRight就是逆序集合,然后调用foldLeft. (Ps:我的scala版本2.9.3)
flodLeft的简写 /:
这个是foldLeft的简写吧,个人理解。
如果我写一个累加的程序
scala> (0/:(1 to 100))(_+_)
res32: Int = 5050
其实是等价于
scala> (1 to 100).foldLeft(0)(_+_)
res33: Int = 5050
foldRight的简写 :\
这个就是foldRight的简写吧,个人理解。
如果我写一个递减的程序
scala> ((1 to 5):\100)((i,sum)=> sum-i)
res51: Int = 85
-EOF-