scala的函數語言程式設計(一)
目錄
引言
函式是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/[email protected] //函式的呼叫 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/[email protected]
scala> val hi = (name : String) => println("hi, " + name)
hi: String => Unit = $$Lambda$1179/[email protected]
scala> val greeting = (func : (String) => Unit , name : String) => func(name)
greeting: (String => Unit, String) => Unit = $$Lambda$1180/[email protected]
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/[email protected]
可以看到“(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/[email protected]
scala> helloFunc("liumingxin")
hello,liumingxin
這裡多說幾句廢話,過於簡潔的程式碼,思維跳躍性也很強,對於新人不太友好,但是函數語言程式設計簡潔的程式碼,能夠提高開發效率,利用scala開發Spark程式的程式碼量比java開發的程式碼量少了5倍不止。scala的函數語言程式設計是比較典型,能夠掌握好scala的函數語言程式設計,學習其他語言的函數語言程式設計都是輕鬆加愉快的事情,所以這裡要慢慢、細緻的學習,還要加以鞏固。