Scala高級特性

Scala高級特性



Scala混合了面向?qū)ο蠛秃瘮?shù)式的特性奏路,我們通常將可以作為參數(shù)傳遞到方法中的表達式叫做函數(shù)畴椰。在函數(shù)式編程語言中,函數(shù)是“頭等公民”鸽粉,高階函數(shù)包含:作為值的函數(shù)斜脂、匿名函數(shù)、閉包触机、柯里化等等帚戳。

[if !supportLists]2.2.? [endif]?作為值的函數(shù)

可以像任何其他數(shù)據(jù)類型一樣被傳遞和操作的函數(shù),每當(dāng)你想要給算法傳入具體動作時這個特性就會變得非常有用儡首。

定義函數(shù)時格式:val 變量名=(輸入?yún)?shù)類型和個數(shù))=>函數(shù)實現(xiàn)和返回值類型

“=”表示將函數(shù)賦給一個變量

“=>”左面表示輸入?yún)?shù)名稱片任、類型和個數(shù),右邊表示函數(shù)的實現(xiàn)和返回值類型

[if !supportLists]2.3.? [endif]?匿名函數(shù)

在Scala中蔬胯,你不需要給每一個函數(shù)命名对供,沒有將函數(shù)賦給變量的函數(shù)叫做匿名函數(shù)。

由于Scala可以自動推斷出參數(shù)的類型氛濒,所有可以寫的跟精簡一些

還記得神奇的下劃線嗎产场?這才是終極方式

[if !supportLists]2.4.? [endif]?柯里化

[if !supportLists]2.4.1.??[endif]?什么是柯里化

柯里化(Currying)指的是把原來接受多個參數(shù)的函數(shù)變換成接受一個參數(shù)的函數(shù)過程,并且返回接受余下的參數(shù)且返回結(jié)果為一個新函數(shù)的技術(shù)舞竿。


[if !supportLists]2.4.2.??[endif]?例子

[if !supportLists](1)????[endif]一個普通的非柯里化的函數(shù)定義京景,實現(xiàn)一個加法函數(shù):


scala> def plainOldSum(x:Int,y:Int)=x+y

plainOldSum: (x: Int, y: Int)Int


scala> plainOldSum(1,2)

res0: Int = 3


[if !supportLists](2)???? [endif]使用“柯里化”技術(shù)來定義這個加法函數(shù),原來函數(shù)使用一個參數(shù)列表骗奖,“柯里化”确徙,把函數(shù)定義為多個參數(shù)列表:

scala> def curriedSum(x:Int)(y:Int)=x+y

curriedSum: (x: Int)(y: Int)Int


scala> curriedSum(1)(2) (等價于下面?zhèn)z句)


val f1 = curriedSum(1) _

f1(2)





當(dāng)你調(diào)用curriedSum (1)(2)時,實際上是依次調(diào)用兩個普通函數(shù)(非柯里化函數(shù))重归,

第一次調(diào)用使用一個參數(shù)x米愿,返回一個函數(shù)類型的值,

第二次使用參數(shù)y調(diào)用這個函數(shù)類型的值鼻吮。


[if !supportLists](3)???? [endif]使用下面兩個分開的定義在模擬curriedSum柯里化函數(shù):

首先定義第一個函數(shù):

scala> def first(x:Int)=(y:Int)=>x+y

first: (x: Int)Int => Int


然后我們使用參數(shù)1調(diào)用這個函數(shù)來生成第二個函數(shù):

scala> val second =first(1)

second: Int => Int =

scala> second(2)

res2: Int = 3



[if !supportLists](4)????[endif]使用curriedSum 來定義second

scala>? val onePlus=curriedSum(1)_

onePlus:

? Int => Int =


下劃線“_” 作為第二參數(shù)列表的占位符育苟, 這個定義的返回值為一個函數(shù),當(dāng)調(diào)用時會給調(diào)用的參數(shù)加一椎木。


scala>? onePlus(2)

res3:? Int = 3

調(diào)用生成的函數(shù)违柏,給函數(shù)傳入?yún)?shù)博烂,即可得到我們想要的結(jié)果。




[if !supportLists]2.4.3.??[endif]?總結(jié)

scala柯里化風(fēng)格的使用可以簡化主函數(shù)的復(fù)雜度漱竖,提高主函數(shù)的自閉性禽篱,提高功能上的可擴張性、靈活性馍惹√陕剩可以編寫出更加抽象,功能化和高效的函數(shù)式代碼。

[if !supportLists]2.5.? [endif]閉包

[if !supportLists]2.5.1.??[endif]?什么是閉包

閉包是一個函數(shù)万矾,返回值依賴于聲明在函數(shù)外部的一個或多個變量悼吱。閉包通常來講可以簡單的認為是可以訪問不在當(dāng)前作用域范圍內(nèi)的一個函數(shù)。

[if !supportLists]2.5.2.??[endif]?例子

package cn.itcast.closure

/**

? * scala中的閉包

? * 閉包是一個函數(shù)良狈,返回值依賴于聲明在函數(shù)外部的一個或多個變量后添。

? */

object ClosureDemo {


def main(args: Array[String]): Unit = {


val y=10


//變量y不處于其有效作用域時,函數(shù)還能夠?qū)ψ兞窟M行訪問


val add=(x:Int)=>{

????????? x+y

??????? }


//在add中有兩個變量:x和y。其中的一個x是函數(shù)的形式參數(shù)薪丁,

??? //在add方法被調(diào)用時遇西,x被賦予一個新的值。

??? // 然而严嗜,y不是形式參數(shù)粱檀,而是自由變量

??? println(add(5)) // 結(jié)果15

? }

}







[if !supportLists]3.??[endif]?隱式轉(zhuǎn)換和隱式參數(shù)

[if !supportLists]3.1.? [endif]??隱式轉(zhuǎn)換

Scala提供的隱式轉(zhuǎn)換和隱式參數(shù)功能,是非常有特色的功能阻问。是Java等編程語言所沒有的功能梧税。它可以允許你手動指定,將某種類型的對象轉(zhuǎn)換成其他類型的對象或者是給一個類增加方法称近。通過這些功能第队,可以實現(xiàn)非常強大、特殊的功能刨秆。

Scala的隱式轉(zhuǎn)換凳谦,其實最核心的就是定義隱式轉(zhuǎn)換方法,即implicit conversion function衡未。定義的隱式轉(zhuǎn)換方法尸执,只要在編寫的程序內(nèi)引入,就會被Scala自動使用缓醋。Scala會根據(jù)隱式轉(zhuǎn)換方法的簽名如失,在程序中使用到隱式轉(zhuǎn)換方法接收的參數(shù)類型定義的對象時,會自動將其傳入隱式轉(zhuǎn)換方法送粱,轉(zhuǎn)換為另外一種類型的對象并返回褪贵。這就是“隱式轉(zhuǎn)換”。其中所有的隱式值和隱式方法必須放到object中。

然而使用Scala的隱式轉(zhuǎn)換是有一定的限制的脆丁,總結(jié)如下:

[if !supportLists]?? [endif]implicit關(guān)鍵字只能用來修飾方法世舰、變量(參數(shù))。

[if !supportLists]?? [endif]隱式轉(zhuǎn)換的方法在當(dāng)前范圍內(nèi)才有效槽卫。如果隱式轉(zhuǎn)換不在當(dāng)前范圍內(nèi)定義(比如定義在另一個類中或包含在某個對象中)跟压,那么必須通過import語句將其導(dǎo)。

[if !supportLists]3.2.? [endif]??隱式參數(shù)

所謂的隱式參數(shù)歼培,指的是在函數(shù)或者方法中震蒋,定義一個用implicit修飾的參數(shù),此時Scala會嘗試找到一個指定類型的丐怯,用implicit修飾的參數(shù)喷好,即隱式值,并注入?yún)?shù)读跷。

Scala會在兩個范圍內(nèi)查找:

[if !supportLists]?? [endif]當(dāng)前作用域內(nèi)可見的val或var定義的隱式變量;

[if !supportLists]?? [endif]一種是隱式參數(shù)類型的伴生對象內(nèi)的隱式值禾唁;



[if !supportLists]3.3.? [endif]??隱式轉(zhuǎn)換方法作用域與導(dǎo)入

(1)Scala默認會使用兩種隱式轉(zhuǎn)換效览,一種是源類型或者目標類型的伴生對象內(nèi)的隱式轉(zhuǎn)換方法;一種是當(dāng)前程序作用域內(nèi)的可以用唯一標識符表示的隱式轉(zhuǎn)換方法荡短。

(2)如果隱式轉(zhuǎn)換方法不在上述兩種情況下的話丐枉,那么就必須手動使用import語法引入某個包下的隱式轉(zhuǎn)換方法,比如import

test._掘托。通常建議瘦锹,僅僅在需要進行隱式轉(zhuǎn)換的地方,用import導(dǎo)入隱式轉(zhuǎn)換方法闪盔,這樣可以縮小隱式轉(zhuǎn)換方法的作用域弯院,避免不需要的隱式轉(zhuǎn)換。

[if !supportLists]3.4.? [endif]??隱式轉(zhuǎn)換的時機

(1)當(dāng)對象調(diào)用類中不存在的方法或成員時泪掀,編譯器會自動將對象進行隱式轉(zhuǎn)換

(2)當(dāng)方法中的參數(shù)的類型與目標類型不一致時


[if !supportLists]3.5.? [endif]??隱式轉(zhuǎn)換和隱式參數(shù)案例

[if !supportLists]① [endif]隱式轉(zhuǎn)換案例一(讓File類具備RichFile類中的read方法)

package cn.itcast.implic_demo

import java.io.File

import scala.io.Source

object MyPredef{

? //定義隱式轉(zhuǎn)換方法


implicit def file2RichFile(file: File)=new RichFile(file)

}

class RichFile(val f:File) {


def read()=Source.fromFile(f).mkString

}

object RichFile{


def main(args: Array[String]) {


val f=new File("E://words.txt")


??//使用import導(dǎo)入隱式轉(zhuǎn)換方法

??? import MyPredef._

? ??//通過隱式轉(zhuǎn)換听绳,讓File類具備了RichFile類中的方法


val content=f.read()

??? println(conte

nt)

? }

}


[if !supportLists]② [endif]隱式轉(zhuǎn)換案例二(超人變身)

package cn.itcast.implic_demo

class Man(val name:String)

class SuperMan(val name: String) {


def heat=print("超人打怪獸")

}

object SuperMan{


//隱式轉(zhuǎn)換方法

? implicit def man2SuperMan(man:Man)=new SuperMan(man.name)


def main(args: Array[String]) {


val hero=new Man("hero")


//Man具備了SuperMan的方法

????? hero.heat

? }

}

[if !supportLists]③ [endif]隱式轉(zhuǎn)換案例三(一個類隱式轉(zhuǎn)換成具有相同方法的多個類)

package cn.itcast.implic_democlass A(c:C) {


def readBook(): Unit ={

????? println(

"A說:好書好書...")

??? }

}

class B(c:C){


def readBook(): Unit ={

??? println(

"B說:看不懂...")

? }


def writeBook(): Unit ={

??? println(

"B說:不會寫...")

? }

}

class C

object AB{


//創(chuàng)建一個類的2個類的隱式轉(zhuǎn)換

? implicit def C2A(c:C)=new A(c)


implicit def C2B(c:C)=new B(c)

}

object B{


def main(args: Array[String]) {


//導(dǎo)包

??? //1. import AB._ 會將AB類下的所有隱式轉(zhuǎn)換導(dǎo)進來

??? //2. import AB._C2A 只導(dǎo)入C類到A類的的隱式轉(zhuǎn)換方法

??? //3. import AB._C2B 只導(dǎo)入C類到B類的的隱式轉(zhuǎn)換方法

??? import AB._


val c=new C


//由于A類與B類中都有readBook(),只能導(dǎo)入其中一個异赫,否則調(diào)用共同方法時代碼報錯

??? //c.readBook()

??? //C

類可以執(zhí)行B類中的writeBook()


c.writeBook()

? }

}

[if !supportLineBreakNewLine]

[endif]

[if !supportLists]④ [endif]隱式參數(shù)案例四(員工領(lǐng)取薪水)

package cn.itcast.implic_demo

object Company{


//在object中定義隱式值??? 注意:同一類型的隱式值只允許出現(xiàn)一次椅挣,否則會報錯

? implicit? valaaa="zhangsan"


implicit? valbbb=10000.00

}

class Boss {


//注意參數(shù)匹配的類型?? 它需要的是String類型的隱式值

? def callName()(implicit name:String):String={

??? name+

" is coming !"


}


//定義一個用implicit修飾的參數(shù)

? //注意參數(shù)匹配的類型??? 它需要的是Double類型的隱式值

? def getMoney()(implicit money:Double):String={


" 當(dāng)月薪水:"+money

? }

}

object Boss extends App{


//使用import導(dǎo)入定義好的隱式值,注意:必須先加載否則會報錯

? import Company._


val boss =new Boss

? println(

boss.callName()+boss.getMoney())

}

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末塔拳,一起剝皮案震驚了整個濱河市鼠证,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌靠抑,老刑警劉巖量九,帶你破解...
    沈念sama閱讀 216,496評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異孕荠,居然都是意外死亡娩鹉,警方通過查閱死者的電腦和手機攻谁,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,407評論 3 392
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來弯予,“玉大人戚宦,你說我怎么就攤上這事⌒饽郏” “怎么了受楼?”我有些...
    開封第一講書人閱讀 162,632評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長呼寸。 經(jīng)常有香客問我艳汽,道長,這世上最難降的妖魔是什么对雪? 我笑而不...
    開封第一講書人閱讀 58,180評論 1 292
  • 正文 為了忘掉前任河狐,我火速辦了婚禮,結(jié)果婚禮上瑟捣,老公的妹妹穿的比我還像新娘馋艺。我一直安慰自己,他們只是感情好迈套,可當(dāng)我...
    茶點故事閱讀 67,198評論 6 388
  • 文/花漫 我一把揭開白布捐祠。 她就那樣靜靜地躺著,像睡著了一般桑李。 火紅的嫁衣襯著肌膚如雪踱蛀。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,165評論 1 299
  • 那天贵白,我揣著相機與錄音率拒,去河邊找鬼。 笑死戒洼,一個胖子當(dāng)著我的面吹牛俏橘,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播圈浇,決...
    沈念sama閱讀 40,052評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼裂问,長吁一口氣:“原來是場噩夢啊……” “哼裕菠!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,910評論 0 274
  • 序言:老撾萬榮一對情侶失蹤落君,失蹤者是張志新(化名)和其女友劉穎亲铡,沒想到半個月后芙盘,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體侦锯,經(jīng)...
    沈念sama閱讀 45,324評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,542評論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了衫贬。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片德澈。...
    茶點故事閱讀 39,711評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖固惯,靈堂內(nèi)的尸體忽然破棺而出梆造,到底是詐尸還是另有隱情,我是刑警寧澤葬毫,帶...
    沈念sama閱讀 35,424評論 5 343
  • 正文 年R本政府宣布镇辉,位于F島的核電站,受9級特大地震影響贴捡,放射性物質(zhì)發(fā)生泄漏忽肛。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,017評論 3 326
  • 文/蒙蒙 一烂斋、第九天 我趴在偏房一處隱蔽的房頂上張望屹逛。 院中可真熱鬧,春花似錦源祈、人聲如沸煎源。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,668評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至歇僧,卻和暖如春图张,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背诈悍。 一陣腳步聲響...
    開封第一講書人閱讀 32,823評論 1 269
  • 我被黑心中介騙來泰國打工祸轮, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人侥钳。 一個月前我還...
    沈念sama閱讀 47,722評論 2 368
  • 正文 我出身青樓适袜,卻偏偏與公主長得像,于是被迫代替她去往敵國和親舷夺。 傳聞我的和親對象是個殘疾皇子苦酱,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,611評論 2 353

推薦閱讀更多精彩內(nèi)容