亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

scala中方法和函數的區別

scala中方法和函數的區別

qq_遁去的一_1 2019-03-06 06:05:13
scala中方法和函數的區別
查看完整描述

2 回答

?
楊__羊羊

TA貢獻1943條經驗 獲得超7個贊

Scala中既有函數也有方法,大多數情況下我們都可以不去理會他們之間的區別。但是有時候我們必須要了解他們之間的不同。


Scala中的方法跟Java的方法一樣,方法是組成類的一部分。方法有名字、類型簽名,有時方法上還有注解,以及方法的功能

實現代碼(字節碼)。


Scala中的函數是一個完整的對象。Scala中用22個特質(trait)抽象出了函數的概念。這22特質從Function1到Function22


如上圖中的Function10代表的是:有10個形參,返回值為R(協變)的函數。

Scala中的函數其實就是繼承了這些Trait的類的對象,如:我們通過函數字面量定義一個函數




其實上述函數的定義方式跟如下定義方式等同:




由于Function2是特質,不能直接new。上述new Function2[Int,Int,Int](){}其實是定義并實例化一個實現了Function2特質的類的對象。

apply是scala中的語法糖:對一個對象obj上調用obj(),scala編譯器會轉換為obj.apply();在一個類clazz上調用clazz(),scala編譯器會轉

換為clazz_company_obj.apply(),其中clazz_company_obj為clazz的伴生對象。


具體的差異,總結為如下幾點:

1.方法不能作為單獨的表達式而存在(參數為空的方法除外),而函數可以。如:




在如上的例子中,我們首先定義了一個方法m,接著有定義了一個函數f。接著我們把函數名(函數值)當作最終表達式來用,由于f本身就是

一個對象(實現了FunctionN特質的對象),所以這種使用方式是完全正確的。但是我們把方法名當成最終表達式來使用的話,就會出錯。

2.函數必須要有參數列表,而方法可以沒有參數列表




在如上的例子中,m1方法接受零個參數,所以可以省略參數列表。而函數不能省略參數列表

3.方法名是方法條用,而函數名只是代表函數對象本身

這個比較容易理解。因為保存函數字面量的變量(又稱為函數名或者函數值)本身就是實現了FunctionN特質的類的對象,要調用對象的apply

方法,就需要使用obj()的語法。所以函數名后面加括號才是調用函數。如下:




4.在需要函數的地方,如果傳遞一個方法,會自動進行ETA展開(把方法轉換為函數)




如果我們直接把一個方法賦值給變量會報錯。如果我們指定變量的類型就是函數,那么就可以通過編譯,如下:




當然我們也可以強制把一個方法轉換給函數,這就用到了scala中的部分應用函數:




5.傳名參數本質上是個方法

傳名參數實質上是一個參數列表為空的方法,如下:




如上代碼實際上定義了一個方法m1,m1的參數是個傳名參數(方法)。由于對于參數為空的方法來說,方法名就是方法調用

,所以List(x,x)實際上是進行了兩次方法調用。




由于List(x,x)是進行了兩次方法調用,所以得到兩個不同的值。




如果我們稍微修改一下函數的m1的定義,把x先緩存起來,結果就會跟以前大不一樣。


 


查看完整回答
反對 回復 2019-03-16
?
慕沐林林

TA貢獻2016條經驗 獲得超9個贊

部分應用函數和偏函數是無關的。經常把部分應用函數(Partial Applied Function)和偏函數(Partial Function) 搞混。
總結如下:
部分應用函數(Partial Applied Function)是缺少部分參數的函數,是一個邏輯上概念

偏函數是只對函數定義域的一個子集進行定義的函數。 scala中用scala.PartialFunction[-T, +S]類來表示
比如定義了一個函數:def sum(x: Int)(y: Int) = x + y, 當調用sum的時候,如果不提供所有的參數或某些參數還未知時,比如sum _ , sum(3)(_: Int), sum(_: Int)(3), 這樣就生成了所謂的部分應用函數。部分應用函數只是邏輯上的一個表達,scala編譯器會用Function1, Function2這些類來表示它.
下面這個變量signal引用了一個偏函數
val signal: PartialFunction[Int, Int] = {
case x if x > 1 => 1
case x if x < -1 => -1
}
這個signal所引用的函數除了0值外,對所有整數都定義了相應的操作。 signal(0) 會拋出異常,因此使用前最好先signal.isDefinedAt(0)判斷一下。 偏函數主要用于這樣一種場景:對某些值現在還無法給出具體的操作(即需求還不明朗),也有可能存在幾種處理方式(視乎具體的需求);我們可以先對需求明確的部分進行定義,比如上述除了0外的所有整數域,然后根據具體情況補充對其他域的定義,比如 :
val composed_signal: PartialFunction[Int,Int] = signal.orElse{
case 0 => 0
}
composed_signal(0) // 返回 0
或者對定義域進行一定的偏移(假如需求做了變更, 1 為無效的點)
val new_signal: Function1[Int, Int] = signal.compose{
case x => x - 1
}
new_signal(1) // throw exception
new_signal(0) // 返回 -1
new_signal(2) // 返回 1
還可以用andThen將兩個相關的偏函數串接起來
val another_signal: PartialFunction[Int, Int] = {
case 0 => 0
case x if x > 0 => x - 1
case x if x < 0 => x + 1
}
val then_signal = another_signal andThen signal
這里的then_signal 剔除了-1, 0, 1三個點的定義



查看完整回答
反對 回復 2019-03-16
  • 2 回答
  • 0 關注
  • 1191 瀏覽

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號