1. 程式人生 > >[譯]Scala方法和函式的區別

[譯]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先快取起來,結果就會跟以前大不一樣。