1. 程式人生 > >scala的函數語言程式設計(一)

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的函數語言程式設計,學習其他語言的函數語言程式設計都是輕鬆加愉快的事情,所以這裡要慢慢、細緻的學習,還要加以鞏固。