目录
引言
函数是scala中最重要的部分,有人愿意称“函数式scala中的一等公民”。也就是因为函数才使得scala更加简洁、优雅、又耐人寻味,总之,函数式编程在scala中是一等一的重要,使用scala开发的各类框架都存在这大量函数,如果想去了解、阅读Spark源码,函数式编程这一关必须要过。吹了好几行的废话,主要意思就是函数在scala中是非常重要的。下面进入正题。
将函数作为值
scala的语法规定,将函数赋值给变量时,必须在函数后面加上空格和下划线。
//正常声明一个带有一个字符串类型参数,并返回Unit类型的方法
scala> def sayHello(name : String) = println("hello,"+name)
sayHello: (name: String)Unit
//将上述方法转换成一个函数,方法后面加上空格和_转变成函数
scala> val sayHelloFun = sayHello _
sayHelloFun: String => Unit = $$Lambda$1049/1571707504@210a26b
//函数的调用
scala> sayHelloFun("liumingxin")
hello,liumingxin
匿名函数
scala中可以不需要给一个函数命名,就像“y = ax + b”我们该叫它啥?其实很多时候函数并不需要一个名字,名字只是一个代号。
匿名函数的创建规则:(参数 : 参数类型) => 函数体
方法的创建规则:def 名称(参数 : 参数类型) = 函数体
这里再提出方法的定义原因有二:1、回顾方法的创建规则;2、对比函数,理解函数和方法创建时的区别“=”和“=>”需要注意
scala> Array(1,2,3,4).map((x : Int) => x * 3)
res3: Array[Int] = Array(3, 6, 9, 12)
//可以将函数参数使用花括号代替圆括号,这样便于区分
scala> Array(1,2,3,4).map{(x : Int) => x * 3}
res4: Array[Int] = Array(3, 6, 9, 12)
在map函数内部的就是匿名函数
函数的高级用法
将函数作为参数
scala> val hello = (name : String) => println("Hello, " + name)
hello: String => Unit = $$Lambda$1178/531068784@62f3ad90
scala> val hi = (name : String) => println("hi, " + name)
hi: String => Unit = $$Lambda$1179/781449501@1a899fcd
scala> val greeting = (func : (String) => Unit , name : String) => func(name)
greeting: (String => Unit, String) => Unit = $$Lambda$1180/1925117845@1f4d9c7f
scala> greeting(hello,"liumingxin")
Hello, liumingxin
scala> greeting(hi,"liumingxin")
hi, liumingxin
从上面代码可以看出greeting函数中第一个参数是“func : (String) => Unit”,它参数名称为"func",func参数是一个函数,这个函数参数类型为String类型,返回值为Unit类型,只要满足这两个条件,都可以作为greeting函数的第一个参数。因此greeting的类型就是"(String => Unit, String) => Unit"。
将函数作为返回值(很重要)
将函数作为返回值,我当时学习这块内容的时候是相当不理解,我很疑惑对于这样一段代码:
“def greetingFunc(msg: String) = (name: String) => println(msg + ", " + name)”,又是“=”又是“=>”乱糟糟的,对于刚学scala的人来说这块阅读和使用起来相当混乱,我认为主要是写得太简练了,省略了太多东西后容易让新人过于混乱。接下来我要介绍的就是如何去理解函数作为返回值。
“def greetingFunc(msg: String) = (name: String) => println(msg + ", " + name)”的语法规则如下:
“def 方法名(参数1 : 参数类型) = (参数2 : String) => 函数体”的形式
我们来回想一下方法定义的完整形式:“def 方法名(参数 : 参数类型) : 返回值类型 = {函数体}”,例如:
scala> def greetingFunc(msg : String) : String = {println(msg + ",liumingxin");m
sg}
greetingFunc: (msg: String)String
scala> greetingFunc("hello")
hello,liumingxin
res2: String = hello
上面代码我们先不看方法的返回值,结合“def greetingFunc(msg: String) = (name: String) => println(msg + ", " + name)”来看,“(name: String) => println(msg + ", " + name)”其实就是方法“greetingFunc(msg : String)”的函数体。理解了这一块,我们再接着往下看。
分析一下“(name: String) => println(msg + ", " + name)”,这个东东的形式是不是有点眼熟?是不是就是匿名函数啊?上面有讲。
“匿名函数的创建规则:(参数 : 参数类型) => 函数体”
scala> (name: String) => println("hello, " + name)
res4: String => Unit = $$Lambda$1057/1988962280@147ad4bb
可以看到“(name: String) => println(msg + ", " + name)”匿名函数的类型是"String => Unit",而“greetingFunc(msg : String)”方法的函数体是“(name: String) => println(msg + ", " + name)”,因此“greetingFunc(msg : String)”方法的返回类型就是“String => Unit”,表示:
“greetingFunc(msg : String)”方法返回的是一个带有String类型的参数返回值类型是Unit的函数
“greetingFunc(msg : String)”方法返回的是一个函数,这个函数式一个带有String类型的参数返回值类型是Unit的函数
看到这,我把“def greetingFunc(msg: String) = (name: String) => println(msg + ", " + name)”这种简化形式还原成完整形式
//根据函数的完整定义形式“def 方法名(参数 : 参数类型) : 返回值类型 = {函数体}”定义方法
//匿名函数的创建规则:(参数 : 参数类型) => 函数体
//“{}”中就是greetingFunc(msg : String)方法的函数体
//这个函数体就是“(name : String) => println(msg + "," + name)”,类型是“String => Unit”
//因此完整形式如下:
def greetingFunc(msg : String) : String => Unit = {(name : String) => println(msg + "," + name)}
//完整版及运行结果
scala> def greetingFunc(msg : String) : String => Unit = {(name : String) => println(msg + "," + name)}
greetingFunc: (msg: String)String => Unit
//简化版及运行结果
scala> def greetingFunc(msg: String) = (name: String) => println(msg + ", " + name)
greetingFunc: (msg: String)String => Unit
到这里我们应该能够很清晰的理解函数作为返回值这一高级特性了。
一个简单的创建和调用的例子:
scala> def greetingFunc(msg : String)= (name:String) => println(msg + "," + name)
greetingFunc: (msg: String)String => Unit
scala> val helloFunc = greetingFunc("hello")
helloFunc: String => Unit = $$Lambda$1067/709531076@71ae1cb
scala> helloFunc("liumingxin")
hello,liumingxin
这里多说几句废话,过于简洁的代码,思维跳跃性也很强,对于新人不太友好,但是函数式编程简洁的代码,能够提高开发效率,利用scala开发Spark程序的代码量比java开发的代码量少了5倍不止。scala的函数式编程是比较典型,能够掌握好scala的函数式编程,学习其他语言的函数式编程都是轻松加愉快的事情,所以这里要慢慢、细致的学习,还要加以巩固。