1、認識
感性的認識一下方法和函數
方法m 是一個邏輯操作快;
函數f 是對象,可以賦值給一個變量或常量;
函數f 有一個=>轉換符號;
2、區分
2-1、函數可作爲一個參數傳入到方法中,而方法不行。
方法m 方法名即是方法調用,有參數需帶參數;
函數f 函數名是函數對象本身,是實現了Function特質的對象,調用需要調apply方法即"()";
object MethodAndFunctionDemo {
//定義一個方法
//方法 m1 參數要求是一個函數,函數的參數必須是兩個Int類型
//返回值類型也是Int類型
def m1(f:(Int,Int) => Int) : Int = {
f(2,6)
}
//定義一個函數f1,參數是兩個Int類型,返回值是一個Int類型
val f1 = (x:Int,y:Int) => x + y
//再定義一個函數f2
val f2 = (m:Int,n:Int) => m * n
//main方法
def main(args: Array[String]): Unit = {
//調用m1方法,並傳入f1函數
val r1 = m1(f1)
println(r1)
//調用m1方法,並傳入f2函數
val r2 = m1(f2)
println(r2)
}
}
運行結果:
8
12
2-2、在Scala中無法直接操作方法,如果要操作方法,必須先將其轉換成函數。
帶參數列表的方法m 不能作爲單獨的表達式而存在,參數爲空的除外;
函數f 可以;
有兩種方法可以將方法轉換成函數:
val f1 = m _
在方法名稱m後面緊跟一個空格和下劃線告訴編譯器將方法m轉換成函數,而不是要調用這個方法。 也可以顯示地告訴編譯器需要將方法轉換成函數:
val f1: (Int) => Int = m
通常情況下編譯器會自動將方法轉換成函數,例如在一個應該傳入函數參數的地方傳入了一個方法,編譯器會自動將傳入的方法轉換成函數。
object TestMap {
def ttt(f:Int => Int):Unit = {
val r = f(10)
println(r)
}
val f0 = (x : Int) => x * x
//定義了一個方法
def m0(x:Int) : Int = {
//傳遞進來的參數乘以10
x * 10
}
//將方法轉換成函數,利用了神奇的下滑線
val f1 = m0 _
def main(args: Array[String]): Unit = {
ttt(f0)
//通過m0 _將方法轉化成函數
ttt(m0 _);
//如果直接傳遞的是方法名稱,scala相當於是把方法轉成了函數
ttt(m0)
//通過x => m0(x)的方式將方法轉化成函數,這個函數是一個匿名函數,等價:(x:Int) => m0(x)
ttt(x => m0(x))
}
}
輸出結果爲:
100
100
100
100
2-3、函數必須要有參數列表,而方法可以沒有參數列表
方法m 可以沒有參數列表;
函數f 必須有;
2-4、在函數出現的地方我們可以提供一個方法
在需要函數的地方或者說指定類型爲函數的地方,傳入一個方法m,會自動轉成函數f;
例如:把一個方法賦值給一個變量或常量,如果沒有指定變量的類型是函數,則會報錯,所以需要指定變量類型爲函數纔會自動轉換方法爲函數;或者過m _
強制轉換方法爲函數。
在需要函數的地方,如果傳遞一個方法,會自動進行ETA展開(把方法轉換爲函數)
如果我們直接把一個方法賦值給變量會報錯。如果我們指定變量的類型就是函數,那麼就可以通過編譯,如下:
當然我們也可以強制把一個方法轉換給函數,這就用到了 scala 中的部分應用函數:
2-5、傳名參數本質上是個方法
上圖方法m1的參數就是傳名參數(方法),由於對於參數爲空的方法來說,方法名就是方法調用,那麼List(x,x)就是是進行了兩次方法x調用。
3、熄燈
方法是一個以def開頭的帶有參數列表(可以無參數列表)的一個邏輯操作塊,這正如object或者class中的成員方法一樣。
函數是一個賦值給一個變量(或者常量)的匿名方法(帶或者不帶參數列表),並且通過
=>
轉換符號帶上邏輯代碼塊的一個表達式。=>
轉換符號後面的邏輯代碼塊的寫法與method的body部分相同。