(数据科学学习手札48)Scala中的函数式编程
一、简介
Scala作为一门函数式编程与面向对象完美结合的语言,函数式编程部分也有其独到之处,本文就将针对Scala中关于函数式编程的一些常用基本内容进行介绍;
二、在Scala中定义函数
2.1 定义函数
和Python相似,Scala中函数的定义和方法(类中的函数称为方法)都以关键词def开始,后面再跟随函数名、函数参数以及参数类型、返回值类型以及函数执行体部分,这是Scala中最常规的函数的定义方法,下面是一个简单的例子:
object main{
def main(args: Array[String]): Unit = {
//定义函数
def plus(a:Double,b:Double):Double={
a + b
}
var result:Double = 0
//调用函数计算结果
result = plus(5,4)
println(result)
}
}
上例中,我们以def关键字开头,定义了一个函数名为plus,传入参数为Double型的a,Double型的b,传出类型为Double型的函数用于计算两个数字之和,运行上述代码,得到对应的结果:
我们也可以定义不含输入参数和返回值的函数:
object main{
def main(args: Array[String]): Unit = {
//定义函数
def demo():Unit={
println("这是个演示函数")
}
demo()
}
}
这时返回值的类型就变为Unit,即无类型,运行结果如下:
当函数执行体部分只有一条语句时,可以直接省略花括号来定义函数,如下面这个例子:
object main{
def compare(a:Double,b:Double)=if(a > b) a else b
def main(args: Array[String]): Unit = {
println("更大的数是"+compare(3,4))
}
}
更特别的,在Scala中我们可以对类中的方法进行条件限制,即先决条件,使用在类中定义方法同等层次下,定义require(表达式内容),来对使用到require中表达式限制的参数进行限制,只有满足条件才会运行对应函数,下面是一个简单的例子:
object main{
class Demo(a:Double,b:Double){
require(a != b)
def compare(): Double ={
if(a > b) a else b
}
}
def main(args: Array[String]): Unit = {
//满足条件地调用
val demo1 = new Demo(a=4,b=3)
println(demo1.compare())
//不满足条件的调用
try{
val demo2 = new Demo(a=4,b=4)
println(demo2.compare())
}catch {
case ex:Exception => println(ex)
}
}
}
可以看出,第一次调用Demo中的compare函数,传入的参数满足 a!=b,因此函数顺利得到执行,而第二次调用时未满足条件,使得程序报错,被错误处理机制所捕获,运行结果如下;
2.2 本地函数
有时候为了函数名之间不发生重名的冲突,我们会在Scala中使用本地函数的机制,顾名思义,本地函数指的是只可以在某部分作用域内调用的函数,如下面这个简单的例子:
object main{ def main(args: Array[String]): Unit = { def X(): Unit ={ //在常规函数内部定义本地函数 def Y(): Unit ={ println("这是本地函数Y") } //在常规函数内部调用本地函数 Y() } def Y(): Unit ={ println("这是非本地函数Y") } //分别调用X,Y X() Y() } }
如上,我们定义了两个函数名均为Y的函数,第一个Y是函数X内部的本地函数,第二个Y是常规函数,当我们在常规函数X中调用其拥有的本地函数Y时,便不会引起与外部同名Y函数之间的冲突,运行结果如下:
2.3 匿名函数
在Scala中也有匿名函数的机制,使得我们只需要书写简单的语句就可以在程序中嵌入需要实现的函数功能,下面是一个简单的例子:
object main{ def main(args: Array[String]): Unit = { //在List的定义过程中使用匿名函数和map方法来转换所有值 var listDemo = List(1,2,3).map((x:Int) => x+1) println(listDemo) } }
在上例中,我们在一个List的定义过程中,利用map方法,将匿名函数 (x:Int) => x+1 广播到List中所有元素之上,运行结果如下:
在Scala中,我们可以将匿名函数作为值进行传递,这称为函数字面量,在函数编译函数字面量的时候才将其实例化为函数值,有些类似类,下面是一个简单的例子:
object main{ def main(args: Array[String]): Unit = { //定义一个匿名函数并将它传递给变量MyFunction var MyFunction = (x:Int,n:Int) => { var result = x for(i <- 1 until n){ result *= x } result } //调用保存匿名函数字面量的变量 var TestValue = MyFunction(2,10) println(TestValue) } }
在上例中,我们定义了一个用于求一个整数若干次方的函数,并将其传递给变量MyFunction,接着调用MyFunction来传入计算结果,作为新变量的值。
2.4 高阶函数
高阶函数是Scala的函数式编程中十分有趣的一部分,它的基本特点是将其他函数作为当前函数的参数来传入,下面是一个简单的关于高阶函数部分特性的例子:
object main{ def main(args: Array[String]): Unit = { //定义函数字面量并赋值 var func1 = (x:Int, n:Int) => { var result = x for(i <- 1 until n){ result *= x } result } //定义高阶函数 def func2(MyFunction:(Int,Int)=>Int,x:Int,n:Int): Int ={ MyFunction(x,n) } //调用高阶函数,传入函数字面量并打印结果 println(func2(func1,2,10)) } }
在上例中我们定义了函数字面量并传递给func1,接着定义了函数func2,设置func2的第一个传入参数为接受两个Int型输入,输出Int型数据的函数,设置func2的2、3个参数为Int型,以对应第一个参数中的函数需要传入的参数,接着我们将函数字面量func1、2,、10作为func2的参数传入func1中,得到了对应的结果。
以上就是Scala中函数式编程的一些基本内容,如有笔误,望指出。