1. 实验室名称:
大数据实验教学系统
2. 实验项目名称:
Scala函数式编程
3. 实验学时:
4. 实验原理:
1、Scala函数
当程序越来越大,你需要将代码细化为小的容易管理的模块。Scala 支持多种方法来细化程序代码,这些方法也为有经验的程序员已经掌握的:使用函数。
Scala中函数可以不依赖于类、对象、接口单独存在,函数可以作为函数的参数、返回值。
2、Scala高阶函数
高阶函数是函数式编程里面一个非常重要的特色,所谓的高阶函数,即某个函数的参数或返回值也是函数,这样的函数被称为”高阶函数”。
5. 实验目的:
掌握Scala函数式编程
掌握Scala常用高阶函数
6. 实验内容:
1、学习使用Scala函数式编程
2、学习Scala高阶函数的应用。
7. 实验器材(设备、虚拟机名称):
硬件:x86_64 ubuntu 16.04服务器
软件:JDK 1.8.162,Scala-2.11.11
8. 实验步骤:
8.1 Scala函数式编程
1、函数字面量。
函数字面量指的是在源代码中的一个未命名函数或匿名函数。在程序中可以像使用一个字符串变量一样使用它。它还可以作为一个输入参数传递给一个高阶方法或高阶函数。另外,它也可以被赋给一个变量。
请启动shell,在paste模式下,键入以下代码:
1. //定义函数 2. (x:Int) => {println("hello");println(x + x)} 3. 4. //一切皆对象,当然函数也是对象,所以可以将它赋给一个变量 5. val func = (x:Int) => {println("hello");println(x + x)} 6. 7. //执行函数 8. func(2)
按下”Ctrl+D”,执行以上代码。输出结果如下:
hello 4
2、定义函数和调用函数。
在Scala中函数可以不依赖于类、对象、接口单独存在,函数可以作为函数的参数、返回值。
在shell中,键入以下代码,定义函数fun1:
1. def fun1(name:String){ 2. println(name) 3. }
执行以上代码。输出结果如下:
fun1: (name: String)Unit
将函数赋值给fun1_v:
1. val fun1_v = fun1 _
执行以上代码。输出结果如下:
fun1_v: String => Unit = <function1>
调用函数fun1:
1. fun1("spark")
执行以下代码。输出结果如下:
spark
调用函数fun1_v:
1. fun1_v("spark")
执行以上代码。输出结果如下:
spark
下面我们定义一个名为”add”的函数,可以实现数字的相加并返回和。在paste模式下,键入以下代码:
1. def add(x:Int,y:Int):Int = { 2. println("这是一个对两个整数进行求和的函数") 3. x + y 4. } 5. 6. // 通过函数名来调用函数(方法) 7. add(4,6)
按下”Ctrl+D”,执行以上代码。输出结果如下:
这是一个对两个整数进行求和的函数
add: (x: Int, y: Int)Int res21: Int = 10
3、匿名函数。
为了使用简洁,将函数直接赋值给变量,使用函数时通过调用变量实现,称为匿名函数。
在paste模式下,键入以下代码:
1. //定义匿名函数 2. val fun2 = (content:String) => println(content) 3. fun2("spark")
按下”Ctrl+D”,执行以上代码。输出结果如下:
spark
8.2 高阶函数
接收函数参数的函数,或者返回函数的函数,称为”高阶函数”。
1、当参数为函数时。
在paste模式下,键入以下代码:
1. //定义匿名函数 2. val hiScala = (content:String) => println(content) 3. 4. //定义高阶函数 5. def bigData(func:(String) => Unit, content:String){ 6. func(content) 7. } 8. 9. // 调用高阶函数 10. bigData(hiScala, "spark")
按下”Ctrl+D”,执行以上代码。输出结果如下:
spark
2、当返回值为函数时。
在paste模式下,键入以下代码:
1. def func_Returned(content:String) = (message:String) => println(content + " " + message) 2. 3. val returned = func_Returned("spark") 4. 5. returned("scala")
按下”Ctrl+D”,执行以上代码。输出结果如下:
spark scala
如果在函数的函数体中,某个输入参数的值只使用了一次,此时可以将参数名称省略,用下划线“_”表示。例如,在paste模式下,键入以下代码:
1. // 定义函数 2. def spark(func:(String) => Unit, name:String){ 3. func(name) 4. } 5. 6. // 调用函数 7. spark((name:String) => println(name), "scala") 8. 9. // 类型推断 10. spark(name => println(name), "scala") 11. 12. // 进一步简化 13. spark(println(_), "scala") 14. 15. // 只有一个参数,直接省略 16. spark(println, "scala")
按下”Ctrl+D”,执行以上代码。输出结果如下:
scala scala scala scala
3、闭包。
当函数的变量超出其有效作用域时,仍然可以对函数内部变量进行访问,这样的函数被称为”闭包”。
例如,在paste模式下,键入以下代码:
1. def scala(content:String) = (message:String) => println(content + " " + message) 2. 3. val funcResult = scala("spark") // 执行完毕后content的内容仍然可以被访问 4. funcResult("flink") // 此时变量content的值Spark超出了函数scala的作用域,但依旧可以成功访问,即为闭包
按下”Ctrl+D”,执行以上代码。输出结果如下:
spark flink
4、函数柯里化。
函数柯里化指的是,把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数而且返回结果的新函数的技术。柯里化本身也用到了闭包。
在paste模式下,键入以下代码:
1. def sum(x:Int, y:Int) = x + y //未柯里化 2. println(sum(1, 2)) 3. 4. def sum_Currying(x:Int) = (y:Int) => x + y //柯里化 5. println(sum_Currying(1)(2)) 6. 7. def sum_Currying_better(x:Int)(y:Int) = x + y //代码简化 8. println(sum_Currying_better(1)(2))
按下”Ctrl+D”,执行以上代码。输出结果如下:
3 3 3
5、嵌套函数
Scala允许用户在函数中定义函数,这称为嵌套函数。其中内部函数称为局部函数。
在paste模式下,键入以下代码:
1. // 函数定义 2. def movieAndDisplay(movieId:Int,movieName:String) = { 3. 4. // 局部函数定义 5. def getMovieDetails(movieId:Int,movieName:String):String = { 6. s" movieId是${movieId},电影名称是${movieName}" 7. } 8. 9. // 局部函数定义 10. def display{ 11. println(getMovieDetails(movieId,movieName)) 12. } 13. 14. // 局部函数调用 15. display 16. } 17. 18. // 外部函数调用 19. movieAndDisplay(123,"东成西就")
按下”Ctrl+D”,执行以上代码。输出结果如下:
movieId是123,电影名称是东成西就
9. 实验结果及分析:
实验结果运行准确,无误
10. 实验结论:
经过本节实验的学习,通过学习Scala函数式编程,进一步巩固了我们的scala基础。
11. 总结及心得体会:
经过本节实验的学习,学习了使用Scala进行函数式编程,掌握了Scala常用高阶函数。函数式编程是用于数据分析(如Spark)的重要编程能力,必须重点掌握。
–end–