大數(shù)據(jù)技術(shù)原理與應(yīng)用課件_第1頁
大數(shù)據(jù)技術(shù)原理與應(yīng)用課件_第2頁
大數(shù)據(jù)技術(shù)原理與應(yīng)用課件_第3頁
大數(shù)據(jù)技術(shù)原理與應(yīng)用課件_第4頁
大數(shù)據(jù)技術(shù)原理與應(yīng)用課件_第5頁
已閱讀5頁,還剩273頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)

文檔簡介

第八章:Scala語言基礎(chǔ)第八章:Scala語言基礎(chǔ)8Scala語言概述1計算機(jī)的緣起2編程范式3Scala簡介8Scala語言概述1計算機(jī)的緣起8.1.1計算機(jī)的緣起數(shù)學(xué)家阿隆佐?邱奇(AlonzoChurch)設(shè)計了“λ演算”,這是一套用于研究函數(shù)定義、函數(shù)應(yīng)用和遞歸的形式系統(tǒng)λ演算被視為最小的通用程序設(shè)計語言λ演算的通用性就體現(xiàn)在,任何一個可計算函數(shù)都能用這種形式來表達(dá)和求值λ演算是一個數(shù)理邏輯形式系統(tǒng),強(qiáng)調(diào)的是變換規(guī)則的運(yùn)用,而非實(shí)現(xiàn)它們的具體機(jī)器8.1.1計算機(jī)的緣起數(shù)學(xué)家阿隆佐?邱奇(AlonzoC8.1.1計算機(jī)的緣起:圖靈機(jī)模型由一個控制器,一條有限長攜帶有信息和運(yùn)算指令帶子的帶子和一個可在帶子上左右移動的讀寫頭組成所有的電子計算機(jī),都沒有超出此模型理想的計算機(jī):毫無停頓的運(yùn)行下去關(guān)鍵問題:數(shù)據(jù)怎么準(zhǔn)備好?依次執(zhí)行(順序)默認(rèn)的執(zhí)行順序跳躍下行(分支)函數(shù)調(diào)用跳躍上行(循環(huán))8.1.1計算機(jī)的緣起:圖靈機(jī)模型由一個控制器,一條有限長8.1.1計算機(jī)的緣起英國數(shù)學(xué)家阿蘭·圖靈采用了完全不同的設(shè)計思路,提出了一種全新的抽象計算模型——圖靈機(jī)圖靈機(jī)是現(xiàn)代計算機(jī)的鼻祖。現(xiàn)有理論已經(jīng)證明,λ演算和圖靈機(jī)的計算能力是等價的8.1.1計算機(jī)的緣起英國數(shù)學(xué)家阿蘭·圖靈采用了完全不同的8.1.1計算機(jī)的緣起馮·諾依曼(JohnVonNeumann)將圖靈的理論物化成為實(shí)際的物理實(shí)體,成為了計算機(jī)體系結(jié)構(gòu)的奠基者1945年6月,馮·諾依曼提出了在數(shù)字計算機(jī)內(nèi)部的存儲器中存放程序的概念,這是所有現(xiàn)代計算機(jī)的范式,被稱為“馮·諾依曼結(jié)構(gòu)”8.1.1計算機(jī)的緣起馮·諾依曼(JohnVonNeu8.1.2編程范式編程范式是指計算機(jī)編程的基本風(fēng)格或典范模式。常見的編程范式主要包括命令式編程和函數(shù)式編程。面向?qū)ο缶幊叹蛯儆诿钍骄幊?,比如C++、Java等命令式語言是植根于馮·諾依曼體系的,一個命令式程序就是一個馮·諾依曼機(jī)的指令序列,給機(jī)器提供一條又一條的命令序列讓其原封不動地執(zhí)行函數(shù)式編程,又稱泛函編程,它將計算機(jī)的計算視為數(shù)學(xué)上的函數(shù)計算函數(shù)編程語言最重要的基礎(chǔ)是λ演算,λ演算對函數(shù)式編程特別是Lisp語言有著巨大的影響。典型的函數(shù)式語言包括Haskell、Erlang和Lisp等8.1.2編程范式編程范式是指計算機(jī)編程的基本風(fēng)格或典范模8.1.2編程范式一個很自然的問題是,既然已經(jīng)有了命令式編程,為什么還需要函數(shù)式編程呢?為什么在C++、Java等命令式編程流行了很多年以后,近些年函數(shù)式編程會迅速升溫呢?命令式編程涉及多線程之間的狀態(tài)共享,需要鎖機(jī)制實(shí)現(xiàn)并發(fā)控制函數(shù)式編程不會在多個線程之間共享狀態(tài),不需要用鎖機(jī)制,可以更好并行處理,充分利用多核CPU并行處理能力8.1.2編程范式一個很自然的問題是,既然已經(jīng)有了命令式編8.1.3Scala簡介Scala是一門類Java的多范式語言,它整合了面向?qū)ο缶幊毯秃瘮?shù)式編程的最佳特性。具體來講:Scala運(yùn)行于Java虛擬機(jī)(JVM)之上,并且兼容現(xiàn)有的Java程序Scala是一門純粹的面向?qū)ο蟮恼Z言Scala也是一門函數(shù)式語言8.1.3Scala簡介Scala是一門類Java的多范式8.2Scala簡介Scala是一門現(xiàn)代的門類Java的多范式編程語言,運(yùn)行于Java平臺(JVM,Java虛擬機(jī)),并兼容現(xiàn)有的Java程序,整合了面向?qū)ο缶幊毯秃瘮?shù)式編程的最佳特性。Scala的特性:Scala具備強(qiáng)大的并發(fā)性,支持函數(shù)式編程,可以更好地支持分布式系統(tǒng)Scala語法簡潔,能提供優(yōu)雅的APIScala兼容Java,運(yùn)行速度快,且能融合到Hadoop生態(tài)圈中

Scala是Spark的主要編程語言,但Spark還支持Java、Python、R作為編程語言Scala的優(yōu)勢是提供了REPL(Read-Eval-PrintLoop,交互式解釋器),提高程序開發(fā)效率8.2Scala簡介Scala是一門現(xiàn)代的門類Java的8.1.4Scala的安裝和使用方法Scala運(yùn)行于Java虛擬機(jī)(JVM)之上,因此只要安裝有相應(yīng)的Java虛擬機(jī),所有的操作系統(tǒng)都可以運(yùn)行Scala程序,包括Window、Linux、Unix、MacOS等。安裝Java安裝Scala使用Scala解釋器第1個Scala程序:HelloWorld8.1.4Scala的安裝和使用方法Scala運(yùn)行于Jav安裝Java直接通過命令安裝OpenJDK7配置JAVA_HOME環(huán)境變量使配置立即生效:安裝Java直接通過命令安裝OpenJDK安裝Scala登錄Scala官網(wǎng),下載scala-8.11.8.tgz把scala命令添加到path環(huán)境變量中啟動Scala解釋器:安裝Scala登錄Scala官網(wǎng),下載sca使用Scala解釋器在Shell命令提示符界面中輸入“scala”命令后,會進(jìn)入scala命令行提示符狀態(tài):可以使用命令“:quit”退出Scala解釋器,如下所示:使用Scala解釋器在Shell命令提示符界第1個Scala程序:HelloWorld注意,上面命令中一定要加入"-classpath.",否則會出現(xiàn)“Nosuchfileorclassonclasspath:HelloWorld”第1個Scala程序:HelloWorld注8.2Scala基礎(chǔ)8.2.1基本語法8.2.2控制結(jié)構(gòu)8.2.3數(shù)據(jù)結(jié)構(gòu)8.8.4面向?qū)ο缶幊袒A(chǔ)8.2.5函數(shù)式編程基礎(chǔ)

8.2Scala基礎(chǔ)8.2.1基本語法8.2.1基本語法聲明值和變量基本數(shù)據(jù)類型和操作Range控制臺輸入輸出語句讀寫文件異常處理8.2.1基本語法聲明值和變量聲明值和變量Scala有兩種類型的變量:val:是不可變的,在聲明時就必須被初始化,而且初始化以后就不能再賦值;var:是可變的,聲明的時候需要進(jìn)行初始化,初始化以后還可以再次對其賦值。聲明值和變量Scala有兩種類型的變量:聲明值和變量聲明值和變量聲明值和變量聲明值和變量聲明值和變量小技巧:如何在Scala解釋器中輸入多行代碼聲明值和變量小技巧:如何在Scala解釋器中基本數(shù)據(jù)類型和操作Scala的數(shù)據(jù)類型包括:Byte、Char、Short、Int、Long、Float、Double和Boolean和Java不同的是,在Scala中,這些類型都是“類”,并且都是包scala的成員,比如,Int的全名是scala.Int。對于字符串,Scala用java.lang.String類來表示字符串基本數(shù)據(jù)類型和操作Scala的數(shù)據(jù)類型包括:基本數(shù)據(jù)類型和操作字面量(literal)基本數(shù)據(jù)類型和操作字面量(literal)基本數(shù)據(jù)類型和操作操作符:在Scala中,可以使用加(+)、減(-)、乘(*)、除(/)、余數(shù)(%)等操作符,而且,這些操作符就是方法。例如,5+3和(5).+(3)是等價的,也就是說:等價于前者是后者的簡寫形式,這里的+是方法名,是Int類中的一個方法。和Java不同,在Scala中并沒有提供++和--操作符,當(dāng)需要遞增和遞減時,可以采用如下方式表達(dá):基本數(shù)據(jù)類型和操作操作符:在Scala中,可基本數(shù)據(jù)類型和操作富包裝類對于基本數(shù)據(jù)類型,除了以上提到的各種操作符外,Scala還提供了許多常用運(yùn)算的方法,只是這些方法不是在基本類里面定義,還是被封裝到一個對應(yīng)的富包裝類中每個基本類型都有一個對應(yīng)的富包裝類,例如Int有一個RichInt類、String有一個RichString類,這些類位于包scala.runtime中當(dāng)對一個基本數(shù)據(jù)類型的對象調(diào)用其富包裝類提供的方法,Scala會自動通過隱式轉(zhuǎn)換將該對象轉(zhuǎn)換為對應(yīng)的富包裝類型,然后再調(diào)用相應(yīng)的方法。例如:3max基本數(shù)據(jù)類型和操作富包裝類對于基本數(shù)據(jù)類型,Range在執(zhí)行for循環(huán)時,我們經(jīng)常會用到數(shù)值序列,比如,i的值從1循環(huán)到5,這時就可以采用Range來實(shí)現(xiàn)Range可以支持創(chuàng)建不同數(shù)據(jù)類型的數(shù)值序列,包括Int、Long、Float、Double、Char、BigInt和BigDecimal等(1)創(chuàng)建一個從1到5的數(shù)值序列,包含區(qū)間終點(diǎn)5,步長為Range在執(zhí)行for循環(huán)時,我們經(jīng)常會用到Range(2)創(chuàng)建一個從1到5的數(shù)值序列,不包含區(qū)間終點(diǎn)5,步長為1(3)創(chuàng)建一個從1到10的數(shù)值序列,包含區(qū)間終點(diǎn)10,步長為2(4)創(chuàng)建一個Float類型的數(shù)值序列,從0.5f到5.9f,步長為0.8fRange(2)創(chuàng)建一個從1到5的數(shù)值序列,控制臺輸入輸出語句為了從控制臺讀寫數(shù)據(jù),可以使用以read為前綴的方法,包括:readInt、readDouble、readByte、readShort、readFloat、readLong、readCharreadBoolean及readLine,分別對應(yīng)9種基本數(shù)據(jù)類型,其中前8種方法沒有參數(shù),readLine可以不提供參數(shù),也可以帶一個字符串參數(shù)的提示所有這些函數(shù)都屬于對象scala.io.StdIn的方法,使用前必須導(dǎo)入,或者直接用全稱進(jìn)行調(diào)用控制臺輸入輸出語句為了從控制臺讀寫數(shù)據(jù),可以使控制臺輸入輸出語句控制臺輸入輸出語句控制臺輸入輸出語句為了向控制臺輸出信息,常用的兩個函數(shù)是print()和println(),可以直接輸出字符串或者其它數(shù)據(jù)類型控制臺輸入輸出語句為了向控制臺輸出信息,常用的控制臺輸入輸出語句Scala還帶有C語言風(fēng)格的格式化字符串的printf()函數(shù)print()、println()和printf()都在對象Predef中定義,該對象默認(rèn)情況下被所有Scala程序引用,因此可以直接使用Predef對象提供的方法,而無需使用scala.Predef.的形式。控制臺輸入輸出語句Scala還帶有C語言風(fēng)格的讀寫文件寫入文件Scala需要使用java.io.PrintWriter實(shí)現(xiàn)把數(shù)據(jù)寫入到文件如果我們想把文件保存到一個指定的目錄下,就需要給出文件路徑讀寫文件寫入文件Scala需要使用java.i讀寫文件讀取文件可以使用Scala.io.Source的getLines方法實(shí)現(xiàn)對文件中所有行的讀取讀寫文件讀取文件可以使用Scala.io.So異常處理Scala仍使用try-catch結(jié)構(gòu)來捕獲異常importjava.io.FileReaderimportjava.io.FileNotFoundExceptionimportjava.io.IOExceptiontry

{

valf=newFileReader("input.txt")

//文件操作}

catch

{

caseex:FileNotFoundException=>

//文件不存在時的操作

caseex:IOException=>

//發(fā)生I/O錯誤時的操作}finally

{

file.close()//確保關(guān)閉文件}

Scala不支持Java中的“受檢查異常”(checkedexception),將所有異常都當(dāng)作“不受檢異?!保ɑ蚍Q為運(yùn)行時異常)異常處理Scala仍使用try-catch結(jié)8.2.2控制結(jié)構(gòu)if條件表達(dá)式while循環(huán)for循環(huán)8.2.2控制結(jié)構(gòu)if條件表達(dá)式if條件表達(dá)式有一點(diǎn)與Java不同的是,Scala中的if表達(dá)式的值可以賦值給變量if條件表達(dá)式有一點(diǎn)與Java不同的是,Scwhile循環(huán)while循環(huán)for循環(huán)Scala中的for循環(huán)語句格式如下:其中,“變量<-表達(dá)式”被稱為“生成器(generator)”for循環(huán)Scala中的for循環(huán)語句格式如for循環(huán)不希望打印出所有的結(jié)果,過濾出一些滿足制定條件的結(jié)果,需要使用到稱為“守衛(wèi)(guard)”的表達(dá)式比如,只輸出1到5之中的所有偶數(shù),可以采用以下語句:for循環(huán)不希望打印出所有的結(jié)果,過濾出一些for循環(huán)Scala也支持“多個生成器”的情形,可以用分號把它們隔開,比如:for循環(huán)Scala也支持“多個生成器”的情for循環(huán)可以給每個生成器都添加一個“守衛(wèi)”,如下:for循環(huán)可以給每個生成器都添加一個“守衛(wèi)”for循環(huán)Scala的for結(jié)構(gòu)可以在每次執(zhí)行的時候創(chuàng)造一個值,然后將包含了所有產(chǎn)生值的集合作為for循環(huán)表達(dá)式的結(jié)果返回,集合的類型由生成器中的集合類型確定通過for循環(huán)遍歷一個或多個集合,對集合中的元素進(jìn)行“推導(dǎo)”,從而計算得到新的集合,用于后續(xù)的其他處理for(變量<-表達(dá)式)yield

{語句塊}for推導(dǎo)式for循環(huán)Scala的for結(jié)構(gòu)可以在每次執(zhí)8.2.3數(shù)據(jù)結(jié)構(gòu)容器(Collection)列表(List)集合(Set)映射(Map)迭代器(Iterator)數(shù)組(Array)元組(Tuple)8.2.3數(shù)據(jù)結(jié)構(gòu)容器(Collectio容器(collection)Scala提供了一套豐富的容器(collection)庫,包括列表(List)、數(shù)組(Array)、集合(Set)、映射(Map)等根據(jù)容器中元素的組織方式和操作方式,可以區(qū)分為有序和無序、可變和不可變等不同的容器類別Scala用了三個包來組織容器類,分別是scala.collection、scala.collection.mutable和scala.collection.immutable容器(collection)Scala提供了容器(collection)下圖顯示了scala.collection包中所有的容器類。這些都是高級抽象類或特質(zhì)。例如,所有容器類的基本特質(zhì)(trait)是Traverable特質(zhì),它為所有的容器類定義了公用的foreach方法,用于對容器元素進(jìn)行遍歷操作容器(collection)下圖顯示了sca容器(collection)下面的圖表顯示了scala.collection.immutable中的所有容器類容器(collection)下面的圖表顯示了容器(collection)下面的圖表顯示scala.collection.mutable中的所有容器類容器(collection)下面的圖表顯示s列表(List)列表是一種共享相同類型的不可變的對象序列。既然是一個不可變的集合,Scala的List定義在scala.collection.immutable包中不同于Java的java.util.List,scala的List一旦被定義,其值就不能改變,因此聲明List時必須初始化varstrList=List("BigData","Hadoop","Spark")列表有頭部和尾部的概念,可以分別使用head和tail方法來獲取head返回的是列表第一個元素的值tail返回的是除第一個元素外的其它值構(gòu)成的新列表,這體現(xiàn)出列表具有遞歸的鏈表結(jié)構(gòu)strList.head將返回字符串”BigData”,strList.tail返回List("Hadoop","Spark")列表(List)列表是一種共享相同類型的不可列表(List)Scala還定義了一個空列表對象Nil,借助Nil,可以將多個元素用操作符::串起來初始化一個列表valintList=1::2::3::Nil與valintList=List(1,2,3)等效構(gòu)造列表常用的方法是通過在已有列表前端增加元素,使用的操作符為::,例如:valotherList="Apache"::strList執(zhí)行該語句后strList保持不變,而otherList將成為一個新的列表:List("Apache","BigData","Hadoop","Spark")列表(List)Scala還定義了一個空列表集合(Set)集合(set)是不重復(fù)元素的容器(collection)。列表中的元素是按照插入的先后順序來組織的,但是,“集合”中的元素并不會記錄元素的插入順序,而是以“哈?!狈椒▽υ氐闹颠M(jìn)行組織,所以,它允許你快速地找到某個元素集合包括可變集和不可變集,分別位于scala.collection.mutable包和scala.collection.immutable包,缺省情況下創(chuàng)建的是不可變集valmySet=Set("Hadoop","Spark“)如果要聲明一個可變集,則需要提前引入scala.collection.mutable.Setimportscala.collection.mutable.SetvarmyMutableSet=Set("Database","BigData")myMutableSet+="CloudComputing"

集合(Set)集合(set)是不重復(fù)元素的容映射(Map)映射(Map)是一系列鍵值對的容器。在一個映射中,鍵是唯一的,但值不一定是唯一的。可以根據(jù)鍵來對值進(jìn)行快速的檢索和集合一樣,Scala采用了類繼承機(jī)制提供了可變的和不可變的兩種版本的映射,分別定義在包scala.collection.mutable和scala.collection.immutable里。默認(rèn)情況下,Scala中使用不可變的映射。如果想使用可變映射,必須明確地導(dǎo)入scala.collection.mutable.Mapvaluniversity=Map(“XMU"->“XiamenUniversity","THU"->"TsinghuaUniversity","PKU"->"PekingUniversity")映射(Map)映射(Map)是一系列鍵值對的映射(Map)如果要獲取映射中的值,可以通過鍵來獲取對于這種訪問方式,如果給定的鍵不存在,則會拋出異常,為此,訪問前可以先調(diào)用contains方法確定鍵是否存在映射(Map)如果要獲取映射中的值,可以通過映射(Map)不可變映射,是無法更新映射中的元素的,也無法增加新的元素。如果要更新映射的元素,就需要定義一個可變的映射也可以使用+=操作來添加新的元素映射(Map)不可變映射,是無法更新映射中的映射(Map)循環(huán)遍歷映射或者,也可以只遍歷映射中的k或者v映射(Map)循環(huán)遍歷映射或者,也可以只遍歷迭代器(Iterator)在Scala中,迭代器(Iterator)不是一個集合,但是,提供了訪問集合的一種方法迭代器包含兩個基本操作:next和hasNext。next可以返回迭代器的下一個元素,hasNext用于檢測是否還有下一個元素迭代器(Iterator)在Scala中,迭迭代器(Iterator)scala>valxs=

List(1,

2,

3,

4,

5)xs:

List[Int]

=

List(1,

2,

3,

4,

5)scala>valgit=xsgrouped3git:

Iterator[List[Int]]

=non-emptyiteratorscala>git.next()res3:

List[Int]

=

List(1,

2,

3)scala>git.next()res4:

List[Int]

=

List(4,

5)scala>valsit=xssliding3sit:

Iterator[List[Int]]

=non-emptyiteratorscala>sit.next()res5:

List[Int]

=

List(1,

2,

3)scala>sit.next()res6:

List[Int]

=

List(2,

3,

4)scala>sit.next()res7:

List[Int]

=

List(3,

4,

5)Iterable有兩個方法返回迭代器:grouped和sliding。然而,這些迭代器返回的不是單個元素,而是原容器(collection)元素的全部子序列。這些最大的子序列作為參數(shù)傳給這些方法。grouped方法返回元素的增量分塊,sliding方法生成一個滑動元素的窗口。兩者之間的差異通過REPL的作用能夠清楚看出。迭代器(Iterator)scala>va數(shù)組(Array)數(shù)組是一種可變的、可索引的、元素具有相同類型的數(shù)據(jù)集合,它是各種高級語言中最常用的數(shù)據(jù)結(jié)構(gòu)。Scala提供了參數(shù)化類型的通用數(shù)組類Array[T],其中T可以是任意的Scala類型,可以通過顯式指定類型或者通過隱式推斷來實(shí)例化一個數(shù)組??梢圆唤o出數(shù)組類型,Scala會自動根據(jù)提供的初始化數(shù)據(jù)來推斷出數(shù)組的類型數(shù)組(Array)數(shù)組是一種可變的、可索引的數(shù)組(Array)Array提供了函數(shù)ofDim來定義二維和三維數(shù)組,用法如下:valmyMatrix=Array.ofDim[Int](3,4)//類型實(shí)際就是Array[Array[Int]]valmyCube=Array.ofDim[String](3,2,4)//類型實(shí)際是Array[Array[Array[Int]]]可以使用多級圓括號來訪問多維數(shù)組的元素,例如myMatrix(0)(1)返回第一行第二列的元素數(shù)組(Array)Array提供了函數(shù)ofD數(shù)組(Array)采用Array類型定義的數(shù)組屬于定長數(shù)組,其數(shù)組長度在初始化后就不能改變。如果要定義變長數(shù)組,需要使用ArrayBuffer參數(shù)類型,其位于包scala.collection.mutable中。舉例如下:importscala.collection.mutable.ArrayBuffervalaMutableArr=ArrayBuffer(10,20,30)aMutableArr+=40

aMutableArr.insert(2,60,40)aMutableArr-=40

vartemp=aMutableArr.remove(2)數(shù)組(Array)采用Array類型定義的數(shù)元組(Tuple)元組是不同類型的值的聚集。元組和列表不同,列表中各個元素必須是相同類型,而元組可以包含不同類型的元素元組(Tuple)元組是不同類型的值的聚集。8.3面向?qū)ο缶幊袒A(chǔ)8.3.1類8.3.2對象8.3.3繼承8.3.4特質(zhì)8.3.5模式匹配8.3面向?qū)ο缶幊袒A(chǔ)8.3.1類8.3.1類簡單的類給類增加字段和方法創(chuàng)建對象編譯和執(zhí)行g(shù)etter和setter方法輔助構(gòu)造器主構(gòu)造器8.3.1類簡單的類簡單的類最簡單的類的定義形式是:可以使用new關(guān)鍵字來生成對象簡單的類最簡單的類的定義形式是:可以使用ne給類增加字段和方法如果大括號里面只有一行語句,那么也可以直接去掉大括號,寫成下面的形式:或者,還可以去掉返回值類型和等號,只保留大括號,如下:Unit后面的等號和大括號后面,包含了該方法要執(zhí)行的具體操作語句給類增加字段和方法如果大括號里面只有一行語句創(chuàng)建對象下面我們新建對象,并調(diào)用其中的方法:從上面代碼可以看出,Scala在調(diào)用無參方法時,是可以省略方法名后面的圓括號的創(chuàng)建對象下面我們新建對象,并調(diào)用其中的方法:編譯和執(zhí)行新建一個TestCounter.scala代碼文件在LinuxShell命令提示符下,使用scala命令執(zhí)行這個代碼文件:上面命令執(zhí)行后,會在屏幕輸出“1”編譯和執(zhí)行新建一個TestCounter.s編譯和執(zhí)行也可以進(jìn)入到Scala解釋器下面去執(zhí)行TestCounter.scala首先啟動Scala解釋器,如下:進(jìn)入scala命令提示符狀態(tài)以后,可以在里面輸入如下命令:完成上面操作以后,可以退出Scala解釋器,回到Linux系統(tǒng)的Shell命令提示符狀態(tài),退出Scala解釋器的命令如下:編譯和執(zhí)行也可以進(jìn)入到Scala解釋器下面去編譯和執(zhí)行下面嘗試一下,看看是否可以使用scalac命令對這個TestCounter.scala文件進(jìn)行編譯,如下:執(zhí)行上述scalac命令后,會出現(xiàn)一堆錯誤,無法編譯。為什么呢?原因:聲明都沒有被封裝在對象中,因此,無法編譯成JVM字節(jié)碼編譯和執(zhí)行下面嘗試一下,看看是否可以使用sc編譯和執(zhí)行在TestCounterJVM.scala中輸入以下代碼:使用scalac命令編譯這個代碼文件,并用scala命令執(zhí)行,如下:上面命令執(zhí)行后,會在屏幕輸出“1”$scalacTestCounterJVM.scala$scala-classpath.MyCounter//MyCounter是包含main方法的對象名稱,這里不能使用文件名稱TestCounterJVM編譯和執(zhí)行在TestCounterJVM.s編譯和執(zhí)行現(xiàn)在我們對之前的類定義繼續(xù)改進(jìn)一下,讓方法中帶有參數(shù)。我們可以修改一下TestCounterJVM.scala文件:編譯執(zhí)行這個文件,就可以得到執(zhí)行結(jié)果是5。編譯和執(zhí)行現(xiàn)在我們對之前的類定義繼續(xù)改進(jìn)一下getter和setter方法給類中的字段設(shè)置值以及讀取值,在Java中是通過getter和setter方法實(shí)現(xiàn)的在Scala中,也提供了getter和setter方法的實(shí)現(xiàn),但是并沒有定義成getXxx和setXxx繼續(xù)修改TestCounterJVM.scala文件:編譯執(zhí)行這個文件,就可以得到兩行執(zhí)行結(jié)果,第一行是0,第二行是4。getter和setter方法給類中的字段設(shè)getter和setter方法但是,在Java中,是不提倡設(shè)置這種公有(public)字段的,一般都是把value字段設(shè)置為private,然后提供getter和setter方法來獲取和設(shè)置字段的值。那么,到了Scala中該怎么做呢?現(xiàn)在我們?nèi)ビ胹calac命令編譯上面的代碼,就會報錯,會出現(xiàn)“error:variablevalueinclassCountercannotbeaccessedinCounter”這樣的錯誤信息。因?yàn)?,value字段前面用了修飾符private,已經(jīng)成為私有字段,外部是無法訪問的。我們先把value字段聲明為private,看看會出現(xiàn)什么效果,繼續(xù)修改TestCounterJVM.scala文件:getter和setter方法但是,在Javgetter和setter方法value變成私有字段以后,Scala又沒有提供getter和setter方法,怎么可以訪問value字段呢?解決方案是,在Scala中,可以通過定義類似getter和setter的方法,分別叫做value和value_=,具體如下:編譯執(zhí)行這個文件,就可以得到三行執(zhí)行結(jié)果,第一行是0,第二行是3,第三行是4。getter和setter方法value變成輔助構(gòu)造器Scala構(gòu)造器包含1個主構(gòu)造器和若干個(0個或多個)輔助構(gòu)造器輔助構(gòu)造器的名稱為this,每個輔助構(gòu)造器都必須調(diào)用一個此前已經(jīng)定義的輔助構(gòu)造器或主構(gòu)造器下面定義一個帶有輔助構(gòu)造器的類,我們對上面的Counter類定義進(jìn)行修改:(代碼未完,剩余代碼見下一頁)輔助構(gòu)造器Scala構(gòu)造器包含1個主構(gòu)造器和輔助構(gòu)造器(代碼續(xù)上一頁)編譯執(zhí)行上述代碼后,得到右邊結(jié)果:輔助構(gòu)造器(代碼續(xù)上一頁)編譯執(zhí)行上述代碼后主構(gòu)造器Scala的每個類都有主構(gòu)造器。但是,Scala的主構(gòu)造器和Java有著明顯的不同,Scala的主構(gòu)造器是整個類體,需要在類名稱后面羅列出構(gòu)造器所需的所有參數(shù),這些參數(shù)被編譯成字段,字段的值就是創(chuàng)建對象時傳入的參數(shù)的值。對于上面給計數(shù)器設(shè)置name和mode的例子,剛才我們是使用輔助構(gòu)造器來對name和mode的值進(jìn)行設(shè)置,現(xiàn)在我們重新來一次,這次我們轉(zhuǎn)而采用主構(gòu)造器來設(shè)置name和mode的值。編譯執(zhí)行上述代碼后,得到結(jié)果:主構(gòu)造器Scala的每個類都有主構(gòu)造器。但是,8.3.2對象單例對象伴生對象應(yīng)用程序?qū)ο骯pply方法和update方法8.3.2對象單例對象單例對象Scala并沒有提供Java那樣的靜態(tài)方法或靜態(tài)字段,但是,可以采用object關(guān)鍵字實(shí)現(xiàn)單例對象,具備和Java靜態(tài)方法同樣的功能。下面是單例對象的定義:可以看出,單例對象的定義和類的定義很相似,明顯的區(qū)分是,用object關(guān)鍵字,而不是用class關(guān)鍵字。單例對象Scala并沒有提供Java那樣的靜單例對象把上述代碼放入到一個test.scala文件中測試在Shell命令提示符下輸入scala命令運(yùn)行上面代碼:執(zhí)行后,屏幕上會顯示以下結(jié)果:單例對象把上述代碼放入到一個test.sca伴生對象在Java中,我們經(jīng)常需要用到同時包含實(shí)例方法和靜態(tài)方法的類,在Scala中可以通過伴生對象來實(shí)現(xiàn)。當(dāng)單例對象與某個類具有相同的名稱時,它被稱為這個類的“伴生對象”。類和它的伴生對象必須存在于同一個文件中,而且可以相互訪問私有成員(字段和方法)。伴生對象在Java中,我們經(jīng)常需要用到同時包伴生對象刪除并重新創(chuàng)建一個test.scala,在該文件中輸入如下代碼:運(yùn)行結(jié)果:伴生對象刪除并重新創(chuàng)建一個test.scal伴生對象從上面結(jié)果可以看出,伴生對象中定義的newPersonId()實(shí)際上就實(shí)現(xiàn)了Java中靜態(tài)(static)方法的功能Scala源代碼編譯后都會變成JVM字節(jié)碼,實(shí)際上,在編譯上面的源代碼文件以后,在Scala里面的class和object在Java層面都會被合二為一,class里面的成員成了實(shí)例成員,object成員成了static成員伴生對象從上面結(jié)果可以看出,伴生對象中定義的伴生對象為了驗(yàn)證這一點(diǎn),我們可以一起測試一下。刪除并重新創(chuàng)建一個test.scala,在該文件中輸入如下代碼:這里做一點(diǎn)小小修改,那就是把objectPerson中的newPersonId()方法前面的private去掉伴生對象為了驗(yàn)證這一點(diǎn),我們可以一起測試一下伴生對象在Shell命令提示符狀態(tài)下,輸入以下命令編譯并執(zhí)行:在目錄下看到兩個編譯后得到的文件,即Person.class和Person$.class。經(jīng)過編譯后,伴生類和伴生對象在JVM中都被合并到了一起執(zhí)行結(jié)果如下:從結(jié)果可以看出,經(jīng)過編譯后,伴生類Person中的成員和伴生對象Person中的成員都被合并到一起,并且,伴生對象中的方法newPersonId(),成為靜態(tài)方法忽略Person$.class,只看Person.class。請使用下面命令進(jìn)行“反編譯”:伴生對象在Shell命令提示符狀態(tài)下,輸入以應(yīng)用程序?qū)ο竺總€Scala應(yīng)用程序都必須從一個對象的main方法開始重新創(chuàng)建一個test.scala,在該文件中輸入如下代碼:為了運(yùn)行上述代碼,我們現(xiàn)在可以使用兩種不同的方法。第一種方法:直接使用scala命令運(yùn)行得到結(jié)果。第二種方法:先編譯再執(zhí)行應(yīng)用程序?qū)ο竺總€Scala應(yīng)用程序都必須從一apply方法和update方法我們經(jīng)常會用到對象的apply方法和update方法,雖然我們表面上并沒有察覺,但是,實(shí)際上,在Scala中,apply方法和update方法都會遵循相關(guān)的約定被調(diào)用,約定如下:用括號傳遞給變量(對象)一個或多個參數(shù)時,Scala會把它轉(zhuǎn)換成對apply方法的調(diào)用當(dāng)對帶有括號并包括一到若干參數(shù)的對象進(jìn)行賦值時,編譯器將調(diào)用對象的update方法,在調(diào)用時,是把括號里的參數(shù)和等號右邊的對象一起作為update方法的輸入?yún)?shù)來執(zhí)行調(diào)用apply方法和update方法我們經(jīng)常會用apply方法和update方法下面我們測試一下apply方法是否被調(diào)用。刪除并重新創(chuàng)建test.scala文件,輸入以下代碼:在Linux系統(tǒng)的Shell命令提示符下運(yùn)行scala命令:運(yùn)行后會得到以下結(jié)果:apply方法和update方法下面我們測試apply方法和update方法上面是類中定義了apply方法,下面看一個在單例對象中定義apply方法的例子:把上面代碼放入到test.scala文件中測試執(zhí)行后,可以得到如下結(jié)果:可以看出,在執(zhí)行TestApplySingleObject("Zhangfei","Liubei")時調(diào)用了apply方法,并且把“ZhangfeiandLiubei”作為返回值,賦值給group變量,因此,println(group)語句會打印出“ZhangfeiandLiubei”。apply方法和update方法上面是類中定apply方法和update方法下面我們測試一個伴生類和伴生對象中的apply方法實(shí)例。刪除并重新創(chuàng)建test.scala文件,輸入以下代碼:執(zhí)行結(jié)果如下:apply方法和update方法下面我們測試apply方法和update方法首先使用scalac編譯命令對test.scala進(jìn)行編譯,然后,使用scala命令運(yùn)行,具體如下:上述代碼執(zhí)行后得到以下結(jié)果:從上面代碼可以看出,當(dāng)我們執(zhí)行vala=ApplyTest()時,會導(dǎo)致apply方法的調(diào)用并返回該方法調(diào)用的值,也就是ApplyTest的實(shí)例化對象。當(dāng)執(zhí)行a()時,又會導(dǎo)致調(diào)用伴生類的apply方法,如果我們愿意,就可以在伴生類的apply方法中寫入一些處理邏輯,這樣就可以把傳入的參數(shù)賦值給實(shí)例化對象的變量。apply方法和update方法首先使用scapply方法和update方法下面看一個apply方法的例子。由于Scala中的Array對象定義了apply方法,因此,我們就可以采用如下方式初始化一個數(shù)組:也就是說,不需要new關(guān)鍵字,不用構(gòu)造器,直接給對象傳遞3個參數(shù),Scala就會轉(zhuǎn)換成對apply方法的調(diào)用,也就是調(diào)用Array類的伴生對象Array的apply方法,完成數(shù)組的初始化。apply方法和update方法下面看一個aapply方法和update方法實(shí)際上,update方法也是類似的,比如:從上面可以看出,在進(jìn)行元組賦值的時候,之所以沒有采用Java中的方括號myStrArr[0],而是采用圓括號的形式,myStrArr(0),是因?yàn)榇嬖谏鲜龅膗pdate方法的機(jī)制。apply方法和update方法實(shí)際上,up8.3.3繼承Scala與Java在繼承方面的區(qū)別抽象類擴(kuò)展類8.3.3繼承Scala與Java在繼承方Scala與Java在繼承方面的區(qū)別Scala中的繼承與Java有著顯著的不同:

(1)重寫一個非抽象方法必須使用override修飾符。

(2)只有主構(gòu)造器可以調(diào)用超類的主構(gòu)造器。

(3)在子類中重寫超類的抽象方法時,不需要使用override關(guān)鍵字。

(4)可以重寫超類中的字段。

Scala和Java一樣,不允許類從多個超類繼承Scala與Java在繼承方面的區(qū)別Scal抽象類以汽車為例子,首先我們創(chuàng)建一個抽象類,讓這個抽象類被其他類繼承。關(guān)于上面的定義,說明幾點(diǎn):

(1)定義一個抽象類,需要使用關(guān)鍵字abstract。

(2)定義一個抽象類的抽象方法,也不需要關(guān)鍵字abstract,只要把方法體空著,不寫方法體就可以。

(3)抽象類中定義的字段,只要沒有給出初始化值,就表示是一個抽象字段,但是,抽象字段必須要聲明類型,比如:valcarBrand:String,就把carBrand聲明為字符串類型,這個時候,不能省略類型,否則編譯會報錯。抽象類以汽車為例子,首先我們創(chuàng)建一個抽象類,擴(kuò)展類抽象類不能直接被實(shí)例化,所以,下面我們定義幾個擴(kuò)展類,它們都是擴(kuò)展了Car類,或者說繼承自Car類。擴(kuò)展類抽象類不能直接被實(shí)例化,所以,下面我們擴(kuò)展類下面,我們把上述代碼放入一個完整的代碼文件test.scala,編譯運(yùn)行。執(zhí)行后,屏幕上會顯示以下結(jié)果:擴(kuò)展類下面,我們把上述代碼放入一個完整的代碼擴(kuò)展類在Shell命令提示符下輸入scala命令運(yùn)行上面代碼:執(zhí)行后,屏幕上會顯示以下結(jié)果:擴(kuò)展類在Shell命令提示符下輸入scala8.3.4特質(zhì)(trait)特質(zhì)概述特質(zhì)的定義把特質(zhì)混入類中特質(zhì)可以包含具體實(shí)現(xiàn)把多個特質(zhì)混入類中8.3.4特質(zhì)(trait)特質(zhì)概述特質(zhì)概述Java中提供了接口,允許一個類實(shí)現(xiàn)任意數(shù)量的接口在Scala中沒有接口的概念,而是提供了“特質(zhì)(trait)”,它不僅實(shí)現(xiàn)了接口的功能,還具備了很多其他的特性Scala的特質(zhì),是代碼重用的基本單元,可以同時擁有抽象方法和具體方法Scala中,一個類只能繼承自一個超類,卻可以實(shí)現(xiàn)多個特質(zhì),從而重用特質(zhì)中的方法和字段,實(shí)現(xiàn)了多重繼承特質(zhì)概述Java中提供了接口,允許一個類實(shí)現(xiàn)特質(zhì)的定義特質(zhì)的定義和類的定義非常相似,有區(qū)別的是,特質(zhì)定義使用關(guān)鍵字trait。上面定義了一個特質(zhì),里面包含一個抽象字段id和抽象方法currentId。注意,抽象方法不需要使用abstract關(guān)鍵字,特質(zhì)中沒有方法體的方法,默認(rèn)就是抽象方法。特質(zhì)的定義特質(zhì)的定義和類的定義非常相似,有區(qū)把特質(zhì)混入類中特質(zhì)定義好以后,就可以使用extends或with關(guān)鍵字把特質(zhì)混入類中。把特質(zhì)混入類中特質(zhì)定義好以后,就可以使用ex把特質(zhì)混入類中下面,我們把上述代碼放入一個完整的代碼文件test.scala,編譯運(yùn)行。執(zhí)行結(jié)果:把特質(zhì)混入類中下面,我們把上述代碼放入一個完特質(zhì)可以包含具體實(shí)現(xiàn)上面的實(shí)例中,特質(zhì)只包含了抽象字段和抽象方法,相當(dāng)于實(shí)現(xiàn)了類似Java接口的功能。實(shí)際上,特質(zhì)也可以包含具體實(shí)現(xiàn),也就是說,特質(zhì)中的字段和方法不一定要是抽象的。特質(zhì)可以包含具體實(shí)現(xiàn)上面的實(shí)例中,特質(zhì)只包含把多個特質(zhì)混入類中上面已經(jīng)定義了兩個特質(zhì)CarId和CarGreeting。可以把兩個特質(zhì)都混入到類中。執(zhí)行結(jié)果如下:把多個特質(zhì)混入類中上面已經(jīng)定義了兩個特質(zhì)Ca8.3.5模式匹配簡單匹配類型模式"守衛(wèi)(guard)"語句for表達(dá)式中的模式case類的匹配Option類型8.3.5模式匹配簡單匹配簡單匹配Scala的模式匹配最常用于match語句中。下面是一個簡單的整型值的匹配實(shí)例。另外,在模式匹配的case語句中,還可以使用變量。執(zhí)行結(jié)果:簡單匹配Scala的模式匹配最常用于matc類型模式Scala可以對表達(dá)式的類型進(jìn)行匹配。執(zhí)行結(jié)果:類型模式Scala可以對表達(dá)式的類型進(jìn)行匹配"守衛(wèi)(guard)"語句可以在模式匹配中添加一些必要的處理邏輯。執(zhí)行結(jié)果:"守衛(wèi)(guard)"語句可以在模式匹配中for表達(dá)式中的模式以我們之前舉過的映射為例子,我們創(chuàng)建的映射如下:循環(huán)遍歷映射的基本格式是:對于遍歷過程得到的每個值,都會被綁定到k和v兩個變量上執(zhí)行結(jié)果:for表達(dá)式中的模式以我們之前舉過的映射為case類的匹配case類是一種特殊的類,它們經(jīng)過優(yōu)化以被用于模式匹配。執(zhí)行結(jié)果:case類的匹配case類是一種特殊的類,Option類型標(biāo)準(zhǔn)類庫中的Option類型用case類來表示那種可能存在、也可能不存在的值。一般而言,對于每種語言來說,都會有一個關(guān)鍵字來表示一個對象引用的是“無”,在Java中使用的是null。Scala融合了函數(shù)式編程風(fēng)格,因此,當(dāng)預(yù)計到變量或者函數(shù)返回值可能不會引用任何值的時候,建議你使用Option類型。Option類包含一個子類Some,當(dāng)存在可以被引用的值的時候,就可以使用Some來包含這個值,例如Some("Hadoop")。而None則被聲明為一個對象,而不是一個類,表示沒有值。Option類型標(biāo)準(zhǔn)類庫中的Option類Option類型下面我們給出一個實(shí)例。Option類型下面我們給出一個實(shí)例。Option類型Option類型還提供了getOrElse方法,這個方法在這個Option是Some的實(shí)例時返回對應(yīng)的值,而在是None的實(shí)例時返回傳入的參數(shù)。例如:可以看出,當(dāng)我們采用getOrElse方法時,如果我們?nèi)〉?hive"沒有對應(yīng)的值,我們就可以顯示我們指定的“NoSuchBook”,而不是顯示None。Option類型Option類型還提供了gOption類型在Scala中,使用Option的情形是非常頻繁的。在Scala里,經(jīng)常會用到Option[T]類型,其中的T可以是Sting或Int或其他各種數(shù)據(jù)類型。Option[T]實(shí)際上就是一個容器,我們可以把它看做是一個集合,只不過這個集合中要么只包含一個元素(被包裝在Some中返回),要么就不存在元素(返回None)。既然是一個集合,我們當(dāng)然可以對它使用map、foreach或者filter等方法。比如:可以發(fā)現(xiàn),上述代碼執(zhí)行后,屏幕上什么都沒有顯示,因?yàn)?,foreach遍歷遇到None的時候,什么也不做,自然不會執(zhí)行println操作。Option類型在Scala中,使用Opt8.4函數(shù)式編程基礎(chǔ)8.4.1函數(shù)定義和高階函數(shù)8.4.2針對集合的操作8.4.3函數(shù)式編程實(shí)例WordCount8.4函數(shù)式編程基礎(chǔ)8.4.1函數(shù)定義和高階函數(shù)8.4.1函數(shù)定義和高階函數(shù)函數(shù)字面量函數(shù)的類型和值匿名函數(shù)、Lamda表達(dá)式與閉包占位符語法8.4.1函數(shù)定義和高階函數(shù)函數(shù)字面量函數(shù)字面量字面量包括整數(shù)字面量、浮點(diǎn)數(shù)字面量、布爾型字面量、字符字面量、字符串字面量、符號字面量、函數(shù)字面量和元組字面量。除了函數(shù)字面量我們會比較陌生以外,其他幾種字面量都很容易理解。函數(shù)字面量字面量包括整數(shù)字面量、浮點(diǎn)數(shù)字面量函數(shù)字面量函數(shù)字面量可以體現(xiàn)函數(shù)式編程的核心理念。在非函數(shù)式編程語言里,函數(shù)的定義包含了“函數(shù)類型”和“值”兩種層面的內(nèi)容。但是,在函數(shù)式編程中,函數(shù)是“頭等公民”,可以像任何其他數(shù)據(jù)類型一樣被傳遞和操作,也就是說,函數(shù)的使用方式和其他數(shù)據(jù)類型的使用方式完全一致了。這時,我們就可以像定義變量那樣去定義一個函數(shù),由此導(dǎo)致的結(jié)果是,函數(shù)也會和其他變量一樣,開始有“值”。就像變量的“類型”和“值”是分開的兩個概念一樣,函數(shù)式編程中,函數(shù)的“類型”和“值”也成為兩個分開的概念,函數(shù)的“值”,就是“函數(shù)字面量”。函數(shù)字面量函數(shù)字面量可以體現(xiàn)函數(shù)式編程的核心函數(shù)的類型和值下面我們一點(diǎn)點(diǎn)引導(dǎo)大家更好地理解函數(shù)的“類型”和“值”的概念。

我們現(xiàn)在定義一個大家比較熟悉的傳統(tǒng)類型的函數(shù),定義的語法和我們之前介紹過的定義“類中的方法”類似(實(shí)際上,定義函數(shù)最常用的方法是作為某個對象的成員,這種函數(shù)被稱為方法):上面定義個這個函數(shù)的“類型”如下:實(shí)際上,只有多個參數(shù)時(不同參數(shù)之間用逗號隔開),圓括號才是必須的,當(dāng)參數(shù)只有一個時,圓括號可以省略,如下:上面就得到了函數(shù)的“類型”函數(shù)的類型和值下面我們一點(diǎn)點(diǎn)引導(dǎo)大家更好地理函數(shù)的類型和值下面看看如何得到函數(shù)的“值”實(shí)際上,我們只要把函數(shù)定義中的類型聲明部分去除,剩下的就是函數(shù)的“值”,如下:注意:上面就是函數(shù)的“值”,需要注意的是,采用“=>”而不是“=”,這是Scala的語法要求。函數(shù)的類型和值下面看看如何得到函數(shù)的“值”實(shí)函數(shù)的類型和值現(xiàn)在,我們再按照大家比較熟悉的定義變量的方式,采用Scala語法來定義一個函數(shù)。

聲明一個變量時,我們采用的形式是:照葫蘆畫瓢,我們也可以按照上面類似的形式來定義Scala中的函數(shù):從上面可以看出,在Scala中,函數(shù)已經(jīng)是“頭等公民”,單獨(dú)剝離出來了“值”的概念,一個函數(shù)“值”就是函數(shù)字面量。這樣,我們只要在某個需要聲明函數(shù)的地方聲明一個函數(shù)類型,在調(diào)用的時候傳一個對應(yīng)的函數(shù)字面量即可,和使用普通變量一模一樣。函數(shù)的類型和值現(xiàn)在,我們再按照大家比較熟悉的匿名函數(shù)、Lamda表達(dá)式與閉包我們不需要給每個函數(shù)命名,這時就可以使用匿名函數(shù),如下:上面這種匿名函數(shù)的定義形式,我們經(jīng)常稱為“Lamda表達(dá)式”?!癓amda表達(dá)式”的形式如下:我們可以直接把匿名函數(shù)存放到變量中,下面是在Scala解釋器中的執(zhí)行過程:匿名函數(shù)、Lamda表達(dá)式與閉包我們不需要給匿名函數(shù)、Lamda表達(dá)式與閉包實(shí)際上,Scala具有類型推斷機(jī)制,可以自動推斷變量類型,比如下面兩條語句都是可以的:所以,上面的定義中,我們可以myNumFunc的類型聲明,也就是去掉“Int=>Int”,在Scala解釋器中的執(zhí)行過程如下:匿名函數(shù)、Lamda表達(dá)式與閉包實(shí)際上,Sc匿名函數(shù)、Lamda表達(dá)式與閉包下面我們再嘗試一下,是否可以繼續(xù)省略num的類型聲明,在Scala解釋器中的執(zhí)行過程如下:可以看出,解釋器會報錯,因?yàn)?,全部省略以后,?shí)際上,解釋器也無法推斷出類型下面我們嘗試一下,省略num的類型聲明,但是,給出myNumFunc的類型聲明,在Scala解釋器中的執(zhí)行過程如下:不會報錯,因?yàn)?,給出了myNumFunc的類型為“Int=>Int”以后,解釋器可以推斷出num類型為Int類型。匿名函數(shù)、Lamda表達(dá)式與閉包下面我們再嘗匿名函數(shù)、Lamda表達(dá)式與閉包閉包是一個函數(shù),一種比較特殊的函數(shù),它和普通的函數(shù)有很大區(qū)別普通函數(shù):閉包:閉包反映了一個從開放到封閉的過程每次addMore函數(shù)被調(diào)用時都會創(chuàng)建一個新閉包每個閉包都會訪問閉包創(chuàng)建時活躍的more變量匿名函數(shù)、Lamda表達(dá)式與閉包閉包是一個函占位符語法為了讓函數(shù)字面量更加簡潔,我們可以使用下劃線作為一個或多個參數(shù)的占位符,只要每個參數(shù)在函數(shù)字面量內(nèi)僅出現(xiàn)一次。從上面運(yùn)行結(jié)果可以看出,下面兩個函數(shù)字面量是等價的。占位符語法為了讓函數(shù)字面量更加簡潔,我們可以占位符語法有時你把下劃線當(dāng)作參數(shù)的占位符時,編譯器有可能沒有足夠的信息推斷缺失的參數(shù)類型。例如,假設(shè)你只是寫_+_:

scala>

val

f

=

_

+

_

<console>:4:

error:

missing

parameter

type

for

expanded

function

((x$1,

x$2)

=>

x$1.$plus(x$2))

val

f

=

_

+

_

這種情況下,你可以運(yùn)用冒號指定類型,如下:

scala>

val

f

=

(_:

Int)

+

(_:

Int)

f:

(Int,

Int)

=>

Int

=

<

function>

scala>

f(5,

10)

res11:

Int

=

15

請留心_+_將擴(kuò)展成帶兩個參數(shù)的函數(shù)字面量。這也是僅當(dāng)每個參數(shù)在函數(shù)字面量中最多出現(xiàn)一次的情況下你才能運(yùn)用這種短格式的原由。多個下劃線指代多個參數(shù),而不是單個參數(shù)的重復(fù)運(yùn)用。第一個下劃線代表第一個參數(shù),第二個下劃線代表第二個,第三個……,如此類推。占位符語法有時你把下劃線當(dāng)作參數(shù)的占位符時,8.4.2針對集合的操作遍歷操作map操作和flatMap操作filter操作reduce操作fold操作8.4.2針對集合的操作遍歷操作遍歷操作列表的遍歷可以使用for循環(huán)進(jìn)行遍歷:也可以使用foreach進(jìn)行遍歷:遍歷操作列表的遍歷可以使用for循環(huán)進(jìn)行遍歷遍歷操作映射的遍歷循環(huán)遍歷映射,是經(jīng)常需要用到的操作,基本格式是:執(zhí)行結(jié)果:創(chuàng)建一個映射循環(huán)遍歷映射遍歷操作映射的遍歷循環(huán)遍歷映射,是經(jīng)常需要用遍歷操作映射的遍歷也可以使用foreach來實(shí)現(xiàn)對映射的遍歷也可以嘗試使用下面形式來遍歷遍歷操作映射的遍歷也可以使用foreach來map操作和flatMap操作map操作是針對集合的典型變換操作,它將某個函數(shù)應(yīng)用到集合中的每個元素,并產(chǎn)生一個結(jié)果集合。map操作map操作和flatMap操作map操作是針map操作和flatMap操作flatMap操作flatMap是map的一種擴(kuò)展。在flatMap中,我們會傳入一個函數(shù),該函數(shù)對每個輸入都會返回一個集合(而不是一個元素),然后,flatMap把生成的多個集合“拍扁”成為一個集合。上面的flatMap執(zhí)行時,會把books中的每個元素都調(diào)用toList,生成List[Char],最終,多個Char的集合被“拍扁”成一個集合。map操作和flatMap操作flatMapfilter操作遍歷一個集合并從中獲取滿足指定條件的元素組成一個新的集合。Scala中可以通過filter操作來實(shí)現(xiàn)。首先創(chuàng)建一個映射:valuniversity=Map("XMU"->"XiamenUniversity","THU"->"TsinghuaUniversity","PKU"->"PekingUniversity","XMUT"->"XiamenUniversityofTechnology")

采用filter操作過濾得到那些學(xué)校名稱中包含“Xiamen”的元素valuniversityOfXiamen=universityfilter{kv=>kv._2contains"Xiamen"}

采用filter操作過濾得到那些學(xué)校名稱中以字母“P”開頭的元素:valuniversityOfP=universityfilter{kv=>kv._2startsWith"P"}

filter操作遍歷一個集合并從中獲取滿足指reduce操作使用reduce這種二元操作對集合中的元素進(jìn)行歸約reduce包含reduceLeft和reduceRight兩種操作,前者從集合的頭部開始操作,后者從集合的尾部開始操作。reduceLeft(_+_)整個加法操作的執(zhí)行順序如下:reduceRight(_+_)表示從列表尾部開始,對兩兩元素進(jìn)行求和操作,順序如下:直接使用reduce,而不用reduceLeft和reduceRight,這時,默認(rèn)采用的是reduceLeftreduce操作使用reduce這種二元操作fold操作折疊(fold)操作和reduce(歸約)操作比較類似。fold操作需要從一個初始的“種子”值開始,并以該值作為上下文,處理集合中的每個元素。fold有兩個變體:foldLeft()和foldRight(),其中,foldLeft(),第一個參數(shù)為累計值,集合遍歷的方向是從左到右。foldRight(),第二個參數(shù)為累計值,集合遍歷的方向是從右到左。對于fold()自身而言,遍歷的順序是未定義的,不過,一般都是從左到右遍歷。fold操作折疊(fold)操作和reduc8.4.3函數(shù)式編程實(shí)例WordCount8.4.3函數(shù)式編程實(shí)例WordCountDepartmentofComputerScience,XiamenUniversity,2017DepartmentofComputerScience第八章:Scala語言基礎(chǔ)第八章:Scala語言基礎(chǔ)8Scala語言概述1計算機(jī)的緣起2編程范式3Scala簡介8Scala語言概述1計算機(jī)的緣起8.1.1計算機(jī)的緣起數(shù)學(xué)家阿隆佐?邱奇(AlonzoChurch)設(shè)計了“λ演算”,這是一套用于研究函數(shù)定義、函數(shù)應(yīng)用和遞歸的形式系統(tǒng)λ演算被視為最小的通用程序設(shè)計語言λ演算的通用性就體現(xiàn)在,任何一個可計算函數(shù)都能用這種形式來表達(dá)和求值λ演算是一個數(shù)理邏輯形式系統(tǒng),強(qiáng)調(diào)的是變換規(guī)則的運(yùn)用,而非實(shí)現(xiàn)它們的具體機(jī)器8.1.1計算機(jī)的緣起數(shù)學(xué)家阿隆佐?邱奇(AlonzoC8.1.1計算機(jī)的緣起:圖靈機(jī)模型由一個控制器,一條有限長攜帶有信息和運(yùn)算指令帶子的帶子和一個可在帶子上左右移動的讀寫頭組成所有的電子計算機(jī),都沒有超出此模型理想的計算機(jī):毫無停頓的運(yùn)行下去關(guān)鍵問題:數(shù)據(jù)怎么準(zhǔn)備好?依次執(zhí)行(順序)默認(rèn)的執(zhí)行順序跳躍下行(分支)函數(shù)調(diào)用跳躍上行(循環(huán))8.1.1計算機(jī)的緣起:圖靈機(jī)模型由一個控制器,一條有限長8.1.1計算機(jī)的緣起英國數(shù)學(xué)家阿蘭·圖靈采用了完全不同的設(shè)計思路,提出了一種全新的抽象計算模型——圖靈機(jī)圖靈機(jī)是現(xiàn)代計算機(jī)的鼻祖?,F(xiàn)有理論已經(jīng)證明,λ演算和圖靈機(jī)的計算能力是等價的8.1.1計算機(jī)的緣起英國數(shù)學(xué)家阿蘭·圖靈采用了完全不同的8.1.1計算機(jī)的緣起馮·諾依曼(JohnVonNeumann)將圖靈的理論物化成為實(shí)際的物理實(shí)體,成為了計算機(jī)體系結(jié)構(gòu)的奠基者1945年6月,馮·諾依曼提出了在數(shù)字計算機(jī)內(nèi)部的存儲器中存放程序的概念,這是所有現(xiàn)代計算機(jī)的范式,被稱為“馮·諾依曼結(jié)構(gòu)”8.1.1計算機(jī)的緣起馮·諾依曼(JohnVonNeu8.1.2編程范式編程范式是指計算機(jī)編程的基本風(fēng)格或典范模式。常見的編程范式主要包括命令式編程和函數(shù)式編程。面向?qū)ο缶幊叹蛯儆诿钍骄幊?,比如C++、Java等命令式語言是植根于馮·諾依曼體系的,一個命令式程序就是一個馮·諾依曼機(jī)的指令序列,給機(jī)器提供一條又一條的命令序列讓其原封不動地執(zhí)行函數(shù)式編程,又稱泛函編程,它將計算機(jī)的計算視為數(shù)學(xué)上的函數(shù)計算函數(shù)編程語言最重要的基礎(chǔ)是λ演算,λ演算對函數(shù)式編程特別是Lisp語言有著巨大的影響。典型的函數(shù)式語言包括Haskell、Erlang和Lisp等8.1.2編程范式編程范式是指計算機(jī)編程的基本風(fēng)格或典范模8.1.2編程范式一個很自然的問題是,既然已經(jīng)有了命令式編程,為什么還需要函數(shù)式編程呢?為什么在C++、Java等命令式編程流行了很多年以后,近些年函數(shù)式編程會迅速升溫呢?命令式編程涉及多線程之間的狀態(tài)共享,需要鎖機(jī)制實(shí)現(xiàn)并發(fā)控制函數(shù)式編程不會在多個線程之間共享狀態(tài),不需要用鎖機(jī)制,可以更好并行處理,充分利用多核CPU并行處理能力8.1.2編程范式一個很自然的問題是,既然已經(jīng)有了命令式編8.1.3Scala簡介Scala是一門類Java的多范式語言,它整合了面向?qū)ο缶幊毯秃瘮?shù)式編程的最佳特性。具體來講:Scala運(yùn)行于Java虛擬機(jī)(JVM)之上,并且兼容現(xiàn)有的Java程序Scala是一門純粹的面向?qū)ο蟮恼Z言Scala也是一門函數(shù)式語言8.1.3Scala簡介Scala是一門類Java的多范式8.2Sc

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論