[TOC]
作为值传递的函数
测试代码如下:
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 = <function2>
- 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://www.bubuko.com/infodetail-2569660.html