您好,登錄后才能下訂單哦!
這篇文章主要講解了“Scala函數(shù)式編程基礎(chǔ)講解”,文中的講解內(nèi)容簡單清晰,易于學(xué)習(xí)與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學(xué)習(xí)“Scala函數(shù)式編程基礎(chǔ)講解”吧!
?
在純函數(shù)式編程語言里,變量就像數(shù)學(xué)語言里的代數(shù)符合,一經(jīng)確定就不能改變。正是由于這種不可變性,使得函數(shù)和普通的值之間具有對等關(guān)系。這樣函數(shù)就跟普通的值一樣成為了“頭等公民”,可以像任何其他數(shù)據(jù)類型一樣被傳遞和操作。
scala不是完全的函數(shù)式編程語言,它在架構(gòu)的上層提倡采用面向?qū)ο缶幊?,而在對?shù)據(jù)和各種底層操作作中使用函數(shù)式編程,對變量的定義既可以使用val,也可以使用var,所以它并不要求變量不可變。但在實(shí)際操作中,scala建議多用val,少用var,這樣可以降低出錯(cuò)的概率。
?
函數(shù)既然與普通的值對等,那么它也應(yīng)該擁有值與類型的區(qū)別。
類型
類型應(yīng)該明確函數(shù)的返回值類型,以及傳入?yún)?shù)的類型
值
值是一個(gè)函數(shù)的具體實(shí)現(xiàn)
比如:
scala> val counter:(Int) => Int = { value => value + 1}val counter: Int => Int = $Lambda$1089/230944166@1372696bscala> counter(5)val res8: Int = 6
上面定義的counter是一個(gè)函數(shù),第2行包括了它的傳入?yún)?shù)類型以及返回值類型定義,即 (Int) => Int
。
符號=>
的左邊是該方法的傳入?yún)?shù)類型,右邊是方法的返回值類型。
等號"=" 后面大括號中的內(nèi)容就是方法體。
當(dāng)函數(shù)需要定義多個(gè)參數(shù)列表時(shí):
scala> def mult(factor:Int)(x:Int) = x*factordef mult(factor: Int)(x: Int): Intscala> mult(90)(5)val res9: Int = 450
當(dāng)一個(gè)函數(shù)包含其它函數(shù)作為參數(shù)或作為返回值時(shí),該函數(shù)稱為高階函數(shù),可以說它是操作其它函數(shù)的函數(shù)。
scala> def sum(f:Int => Int, a:Int, b:Int):Int = { if(a>b) 0 else f(a)+sum(f,a+1,b)}def sum(f: Int => Int, a: Int, b: Int): Intscala> sum(x=>x*x, 1, 5)val res10: Int = 55
上面函數(shù)的計(jì)算過程:
初始時(shí) a = 1, b = 5
sum(x=>x*x, 1, 5)
= f(1) + sum(f, 2, 5) = 1 + f(2) +sum(f, 3, 5) = 1 + 4 + f(3) + sum(4,5)
= 1 + 4 +9 + f(4) + sum (5,5) = 1 + 4 + 9 + 16 + f(5) + sum(6,5)
= 1+ 4 + 9 + 16 + 25 + 0 = 55
有些函數(shù)的執(zhí)行只依賴于傳入?yún)?shù)的值,與調(diào)用函數(shù)的上下文無關(guān)。當(dāng)函數(shù)執(zhí)行時(shí)依賴于聲明于函數(shù)外部的變量時(shí),則稱這個(gè)函數(shù)為閉包。
偏應(yīng)用函數(shù)
一個(gè)函數(shù)在特殊應(yīng)用場景下參數(shù)可能會多次取相同的值,將這個(gè)函數(shù)的部分參數(shù)整合為一個(gè)參數(shù),傳入一個(gè)新的函數(shù)中,這就稱為偏應(yīng)用函數(shù)。
scala> def sum(a:Int, b:Int, c:Int):Int = { a+b+c}def sum(a: Int, b: Int, c: Int): Intscala> sum(1,2,3)val res21: Int = 6scala> sum(1,2,4)val res22: Int = 7scala> val a = sum(1,2,_:Int)val a: Int => Int = $Lambda$1114/1028466661@5dd12d01scala> a(9)val res23: Int = 12
定義一個(gè)新的變量a, 它將原本sum函數(shù)的第1、2個(gè)傳入?yún)?shù)的值固定了,然后我們調(diào)用的時(shí)候只需要向 a 傳入原本sum函數(shù)中的第3個(gè)參數(shù)就可以了。
Curry化
Curry化的函數(shù)是指一個(gè)函數(shù)擁有多個(gè)參數(shù)列表,并且每個(gè)參數(shù)列表中只有一個(gè)參數(shù)。
遍歷
scala標(biāo)準(zhǔn)的容器遍歷方法為foreach方法。該方法的原型為:def foreach[U](f: Elem => U): Unit
先來看一個(gè)例子:
scala> var list = List(1,2,3) //創(chuàng)建一個(gè)List容器var list: List[Int] = List(1, 2, 3)scala> var f = (i:Int) => println(i)var f: Int => Unit = $Lambda$1122/1187220855@4ad30ac5scala> list.foreach(f)123
可以看到,foreach方法返回值類型為Unit,該函數(shù)接受一個(gè)函數(shù)f 作為參數(shù)。
函數(shù)f 的傳入?yún)?shù)類型為Elem,即容器中元素的類型;然后返回值類型為Unit。
在這個(gè)例子中,我們遍歷了List容器中的元素,其元素類型為Int。傳入foreach函數(shù)的函數(shù)參數(shù) f 的功能是打印元素。
我們還可以使用中綴表示法來調(diào)用 foreach:格式為容器 foreach 應(yīng)用在容器上的方法
scala> list foreach println123
映射
映射是指通過對容器中的元素進(jìn)行某些運(yùn)算來生成一個(gè)新的容器。scala中有兩個(gè)典型的映射方法:map 方法和flatMap方法。
map方法對集合中每個(gè)元素進(jìn)行指定運(yùn)算生成新的元素,會返回一個(gè)與原容器同樣類型和大小的新容器。
scala> val bao = List("chen","rui","bo")val bao: List[String] = List(chen, rui, bo)scala> bao.map(s => s.length)val res32: List[Int] = List(4, 3, 2)
flatMap方法對集合中每個(gè)元素進(jìn)行指定運(yùn)算,然后對于每個(gè)元素都會返回一個(gè)容器,最后把生成的所有容器合并成為一個(gè)容器并返回。返回容器的類型與原容器相同,但大小可能不同,其中元素類型也可能不同。
scala> bao.flatMap(s => s.toList)val res36: List[Char] = List(c, h, e, n, r, u, i, b, o)
ps: List是一個(gè)列表,會存儲重復(fù)元素。
?
過濾
過濾,顧名思義就是根據(jù)實(shí)際需求對容器中的元素進(jìn)行篩選。scala中最經(jīng)典的過濾方法是 filter,exists以及find 。
下面舉個(gè)例子來看看怎么使用filter :
scala> val university = Map("XMU"->"Xiamen University","THU"->"Tsinghua University", "PKU"->"Peking University")val university: scala.collection.immutable.Map[String,String] = Map(XMU -> Xiamen University, THU -> Tsinghua University, PKU -> Peking University)scala> f = university filter{ kv => kv._2 contains "Xiamen"} val res39: scala.collection.immutable.Map[String,String] = Map(XMU -> Xiamen University)
整個(gè)過程就是,首先創(chuàng)建一個(gè)Map容器,然后遍歷整個(gè)容器,查找值含有"Xiamen"的鍵值對,進(jìn)行過濾,得到一個(gè)新的Map容器。其中kv._2
用于訪問某個(gè)鍵值對的值,相應(yīng)地,如果要訪問該鍵值對的鍵,則使用kv._1
。
類似的,exists 用于查找容器中是否含有某個(gè)元素,find 用于查找第一個(gè)符合條件的元素。
?
規(guī)約
規(guī)約是對容器的元素進(jìn)行兩兩運(yùn)算,將其“規(guī)約”為一個(gè)值。
先來看看最常用的reduce 方法:
scala> val list = List(1,2,3,4,5)val list: List[Int] = List(1, 2, 3, 4, 5)scala> list.reduce(_+_)val res41: Int = 15
reduce接收了一個(gè)二元函數(shù)f (帶有2個(gè)元素) 作為參數(shù),然后進(jìn)行運(yùn)算,最后結(jié)果為15,這個(gè)過程可以表示為:((((1+2)+3)+4)+5)
。
所以reduce第一次接受的元素分別是1和2,然后是3和3,接著是6和4,最后是10和5,每次都將接受的兩個(gè)元素相加,然后再將相加的結(jié)果作為下一次接收的兩個(gè)元素中的第一個(gè),規(guī)約操作進(jìn)行到容器中的元素遍歷完成為止。
?
?
對于List這樣的元素有序的容器做規(guī)約,reduce默認(rèn)的順序?yàn)閺淖蟮接?,若要自定義遍歷順序,可以使用reduceLeft或者reduceRight。規(guī)約結(jié)果跟進(jìn)行的運(yùn)算以及規(guī)約順序也有關(guān)系,加法和乘法遵循交換律和結(jié)合律,從左到右和從右到左并沒有區(qū)別,而對于減法就有區(qū)別了。
對于Set這種元素?zé)o序的容器做規(guī)約,由于順序未定,其最后結(jié)果可能是不確定的。
與reduce相似的規(guī)約方法還有fold。
拆分
拆分操作將容器中的元素按照一定規(guī)則分割成多個(gè)子容器。常用的拆分方法有:partition、groupedBy、grouped和sliding。
partition方法接受一個(gè)布爾函數(shù),遍歷容器并使用該布爾函數(shù)判斷每個(gè)元素是否符合條件,然后以二元組的方式返回兩個(gè)容器,分別為滿足條件的元素集合和不滿足條件的元素集合。
scala> val list = List(1,2,3,4,5,6,7)val list: List[Int] = List(1, 2, 3, 4, 5, 6, 7)scala> list.partition(_<4)val res42: (List[Int], List[Int]) = (List(1, 2, 3),List(4, 5, 6, 7))
groupedBy方法接收一個(gè)返回Unit類型的函數(shù),用該函數(shù)對容器元素進(jìn)行遍歷,將返回值相同的元素作為一個(gè)子容器,并與該相同的值構(gòu)成一個(gè)HashMap鍵值對,最后返回的形式為:Map[U,C[T]]。
scala> val gby = list.groupBy(x=>x%3)val gby: scala.collection.immutable.Map[Int,List[Int]] = HashMap(0 -> List(3, 6), 1 -> List(1, 4, 7), 2 -> List(2, 5))
grouped 方法接收一個(gè)整型參數(shù) n,按從左到右的順序?qū)⑷萜鲃澐譃槎鄠€(gè)大小為n的子容器,最后一個(gè)容器的大小可能不足n,然后返回由子容器構(gòu)成的迭代器。
scala> val group = list.grouped(2)val group: Iterator[List[Int]] = <iterator>scala> group foreach println List(1, 2)List(3, 4)List(5, 6)List(7)
sliding方法接收一個(gè)整型參數(shù) n,按從左到右的順序?qū)⑷萜鹘厝槎鄠€(gè)長度為n的滑動(dòng)窗口,返回由子容器構(gòu)成的迭代器。
scala> val slidingwindow = list.sliding(3)val slidingwindow: Iterator[List[Int]] = <iterator>scala> slidingwindow foreach println List(1, 2, 3)List(2, 3, 4)List(3, 4, 5)List(4, 5, 6)List(5, 6, 7)
??
感謝各位的閱讀,以上就是“Scala函數(shù)式編程基礎(chǔ)講解”的內(nèi)容了,經(jīng)過本文的學(xué)習(xí)后,相信大家對Scala函數(shù)式編程基礎(chǔ)講解這一問題有了更深刻的體會,具體使用情況還需要大家實(shí)踐驗(yàn)證。這里是億速云,小編將為大家推送更多相關(guān)知識點(diǎn)的文章,歡迎關(guān)注!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。