Scala笔记整理(五):函数式编程
[TOC]
金华网站建设公司创新互联建站,金华网站设计制作,有大型网站制作公司丰富经验。已为金华近1000家提供企业网站建设服务。企业网站搭建\外贸营销网站建设要多少钱,请找那个售后服务好的金华做网站的公司定做!
作为值传递的函数
测试代码如下:
package cn.xpleaf.bigdata.p4.function
/**
* scala中关于函数的操作
*/
object _01FunctionOps {
def main(args: Array[String]): Unit = {
functionOps1
}
/**
* 作为值传递的函数
* 将一个函数作为值传递给另外一个函数变量的时候,约定需要在函数后面加上:空格和下划线
* 相当于数据库中的别名,或者数据库表对应的视图
*/
def functionOps1: Unit = {
def sayHi(name:String) = println("Hello, " + name)
def sayHello = sayHi _
sayHello("xpleaf")
}
}
输出结果如下:
Hello, xpleaf
匿名函数
测试代码如下:
package cn.xpleaf.bigdata.p4.function
/**
* scala中关于函数的操作
*/
object _01FunctionOps {
def main(args: Array[String]): Unit = {
functionOps2
}
/**
* 匿名函数,说白了就是没有函数名字
* 匿名函数就和java中的匿名内部类一样,是只适合使用一次的函数
* 一般如果一个函数的参数是一个函数,这种情况下多用匿名函数来作为参数进行传递
*/
def functionOps2: Unit = {
val printName = (name:String) => println("你好," + name)
printName("xpleaf")
}
}
输出结果如下:
你好,xpleaf
其实前面在学习ArrayBuffer的时候已经有使用过匿名函数:
scala> val ab = ArrayBuffer[Int](3, 8, 2, 20, 5, 7)
ab: scala.collection.mutable.ArrayBuffer[Int] = ArrayBuffer(3, 8, 2, 20, 5, 7)
scala> ab.sortWith((v1, v2) => v1 > v2)
res209: scala.collection.mutable.ArrayBuffer[Int] = ArrayBuffer(20, 8, 7, 5, 3, 2)
带函数参数的函数(高阶函数)
说明的作用有两个(匿名函数作为参数和返回值为匿名函数),具体参考下面的测试代码:
package cn.xpleaf.bigdata.p4.function
/**
* scala中关于函数的操作
*/
object _01FunctionOps {
def main(args: Array[String]): Unit = {
// functionOps1
// functionOps2
functionOps3
}
/**
* scala的高阶函数,就是函数的 [参数是函数] 的函数,把这种函数称为高阶函数
*/
def functionOps3: Unit = {
// 1.匿名函数作为参数
def highOrderFunc(name:String, func:(String) => Unit): Unit = {
func(name)
}
highOrderFunc("xpleaf", (name:String) => println("Hello, " + name))
// 2.将匿名函数作为返回值传递给另外一个函数
def getGoodBayFunction(gMsg: String) = (gName: String) => println(gMsg + ", " + gName)
val goodbayFunction = getGoodBayFunction("good bye")
goodbayFunction("xpleaf")
}
}
输出结果如下:
Hello, xpleaf
good bye, xpleaf
参数(类型)推断
测试代码如下:
package cn.xpleaf.bigdata.p4.function
import scala.collection.mutable.ArrayBuffer
/**
* scala中关于函数的操作
*/
object _01FunctionOps {
def main(args: Array[String]): Unit = {
// functionOps1
// functionOps2
// functionOps3
functionOps4
}
/**
* 对于匿名函数的省略写法
*/
def functionOps4: Unit = {
val ab = ArrayBuffer[Int](1, 2, 3, 4, 5)
// val newAB = ab.map((x:Int) => x * 100)
// val newAB = ab.map((x) => x * 100)
// val newAB = ab.map(x => x * 100)
val newAB = ab.map(100 * _)
println(newAB) // ArrayBuffer(100, 200, 300, 400, 500)
}
}
输出结果如下:
ArrayBuffer(100, 200, 300, 400, 500)
常见高阶函数——map函数
遍历集合中的每一个元素,返回也是一个集合,集合大小和之前集合相等。
- 快速产生0.1, 0.2, 0.3等方式的数字
scala> (1 to 9).map(0.1 * _).foreach(println(_))
0.1
0.2
0.30000000000000004
0.4
0.5
0.6000000000000001
0.7000000000000001
0.8
0.9
- 打印三角形
scala> (1 to 9).map("*" * _).foreach(println(_))
*
**
***
****
*****
******
*******
********
*********
在这里,我们还用到了foreach,它和map很像,只不过它的函数并不返回任何值,foreach只是简单的将函数应用到每个元素而已。
常见高阶函数——filter函数
按照过滤条件,将原集合中不符合条件的数据过滤掉
- 输出所有匹配某个特定条件的元素,得到一个序列中的所有偶数
scala> (1 to 9).filter(line => line % 2 == 0).foreach(println(_))
2
4
6
8
scala> (1 to 9).filter(_ % 2 ==0).foreach(println)
2
4
6
8
常见高阶函数——reduce函数
scala> (1 to 9).reduce((v1:Int, v2:Int) => v1 + v2)
res4: Int = 45
scala> (1 to 9).reduce(_ + _)
res6: Int = 45
scala> (1 to 9).reduceLeft(_ + _)
res7: Int = 45
scala> (1 to 9).reduceRight(_ + _)
res8: Int = 45
可以写下面一个函数来验证reduce函数的执行过程:
scala> val process = (v1:Int, v2:Int) => println(s"v1=${v1}, v2=${v2}")
process: (Int, Int) => Unit =
scala> def pro(v1:Int, v2:Int):Int = {
| println(s"v1=${v1}, v2=${v2}")
| v1 + v2
| }
pro: (v1: Int, v2: Int)Int
- reduce的执行流程
scala> (1 to 9).reduce((v1:Int, v2:Int) => pro(v1, v2))
v1=1, v2=2
v1=3, v2=3
v1=6, v2=4
v1=10, v2=5
v1=15, v2=6
v1=21, v2=7
v1=28, v2=8
v1=36, v2=9
res0: Int = 45
- reductLeft的执行流程
scala> (1 to 9).reduceLeft((v1:Int, v2:Int) => pro(v1, v2))
v1=1, v2=2
v1=3, v2=3
v1=6, v2=4
v1=10, v2=5
v1=15, v2=6
v1=21, v2=7
v1=28, v2=8
v1=36, v2=9
res2: Int = 45
- reductRight的执行流程
scala> (1 to 9).reduceRight((v1:Int, v2:Int) => pro(v1, v2))
v1=8, v2=9
v1=7, v2=17
v1=6, v2=24
v1=5, v2=30
v1=4, v2=35
v1=3, v2=39
v1=2, v2=42
v1=1, v2=44
res3: Int = 45
这样的话执行过程就非常清晰了,reduce和reduceLeft都是从左边的操作数开始,而reduceRight是从右边的操作数开始。
常见高阶函数——sortWith函数
scala> (1 to 9).sortWith((v1:Int, v2:Int) => v1 > v2).foreach(println(_))
9
8
7
6
5
4
3
2
1
scala> (1 to 9).sortWith(_ > _).foreach(println)
9
8
7
6
5
4
3
2
1
闭包
函数的变量不在其作用域内被调用,就是闭包的概念,看下面一个例子:
def closePackage: Unit ={
def mulBy(factor:Double) = (x:Double) => factor * x
val triple = mulBy(3)
val half = mulBy(0.5)
println(triple(14) +" " + half(14)) //42, 7
}
1)mulBy的首次调用将参数变量factor设为3,。该变量在(x:Double)=>factor *x
函数的函数体内被引用。该函数被存入triple.然后参数变量factor从运行时的栈上被弹出。
2)mulBy再次被调用,这次factor被设为0.5.该变量在(x:Double)=>factor *x
函数的函数体内被引用,该函数被存入half.
每一个函数被称为闭包(closure)。闭包有代码和代码用到的任何非局部变量定义构成。
其实上面的mulBy
函数就类似于下面这个:
def mulBy1(factor:Double, x:Double) = {
factor * x
}
原本还希望进一步写成下面这样子的:
def mulBy2(factor:Double, x:Double) = {
def work(x:Double) = {
factor * x
}
return work
}
但在scala中不支持这样的写法,下面这样写才可以:
def mulBy2(factor:Double) = {
(x:Double) => factor * x
}
// 加个return也不行
之前在Python中使用过闭包,类似上面的例子,Python就可以这样写:
def mulBy(factor):
def work(x):
return factor * x
return work
测试如下:
>>> def mulBy(factor):
... def work(x):
... return factor * x
... return work
...
>>> triple = mulBy(3)
>>> half = mulBy(0.5)
>>> triple(14)
42
>>> half(14)
7.0
当然,只是Python的语法格式就没有scala那么灵活了。
柯里化(currying函数)
1、柯里化(currying)指的是将原来接受2个参数的函数变成新的接受一个参数的函数的过程。新的函数返回一个以原有第二个参数作为参数的函数。
2、在函数调用的过程中,就变为了两个函数连续调用的形式。在Spark源码中,也有体现,所以对()()这种形式的Curring函数,一定要掌握。
以下函数接受一个参数,生成另一个接受单个参数的函数,要计算两个数的乘积,调用如下:
/**
* curryingFunction: 柯里化函数
*/
def curryingFunction ={
def totalSum(x:Int, y:Int) = println( x + y)
//totalSum(4,5)
def totalSumAtTime(x:Int) = (y:Int) => x + y
println(totalSumAtTime(4)(5))
}
网站栏目:Scala笔记整理(五):函数式编程
网页网址:http://hbruida.cn/article/podocg.html