方法能夠做爲一個表達式的一部分出現(調用函數並傳參),可是方法(帶參方法)不能做爲最終的表達式,express
可是函數能夠做爲最終的表達式出現:緩存
scala> //定義一個方法app
scala> def m(x:Int) = 2*xdom
m: (x: Int)Int函數
scala> //定義一個函數this
scala> val f = (x:Int) => 2*xscala
f: Int => Int = <function1>it
scala> //方法不能做爲最終表達式出現io
scala> mconsole
<console>:9: error: missing arguments for method m;
follow this method with `_‘ if you want to treat it as a partially applied function
m
^
scala> //函數能夠做爲最終表達式出現
scala> f
res9: Int => Int = <function1>
無參方法能夠做爲最終表達式出現,其實這屬於方法調用,scala規定無參函數的調用能夠省略括號
(關於方法調用咱們下面會涉及到)
scala> def m1()=1+2
m1: ()Int
scala> m1
res10: Int = 3
參數列表對於方法是可選的,可是對於函數是強制的
方法的能夠沒有參數列表,參數列表也能夠爲空。可是函數必須有參數列表(也能夠爲空),見下面例子
scala> //方法能夠沒有參數列表
scala> def m2 = 100;
m2: Int
scala> //方法能夠有一個空的參數列表
scala> def m3() = 100
m3: ()Int
scala> //函數必須有參數列表,不然報錯
scala> var f1 = => 100
<console>:1: error: illegal start of simple expression
var f1 = => 100
^
scala> //函數也能夠有一個空的參數列表
scala> var f2 = () => 100
f2: () => Int = <function0>
那麼方法爲何能夠沒有參數列表呢,往下看。
方法名意味着方法調用,函數名只是表明函數自身
由於方法不能做爲最終的表達式存在,因此若是你寫了一個方法的名字而且該方法不帶參數(沒有參數列表或者無參)
該表達式的意思是:調用該方法獲得最終的表達式。由於函數能夠做爲最終表達式出現,若是你寫下函數的名字,函數
調用並不會發生,該方法自身將做爲最終的表達式進行返回,若是要強制調用一個函數,你必須在函數名後面寫()
scala> //該方法沒有參數列表
scala> m2
res11: Int = 100
scala> //該方法有一個空的參數列表
scala> m3
res12: Int = 100
scala> //獲得函數自身,不會發生函數調用
scala> f2
res13: () => Int = <function0>
scala> //調用函數
scala> f2()
res14: Int = 100
爲何在函數出現的地方咱們能夠提供一個方法
在scala中不少高級函數,如map(),filter()等,都是要求提供一個函數做爲參數。可是爲何咱們能夠提供一個方法呢
?就像下面這樣:
scala> val myList = List(3,56,1,4,72)
myList: List[Int] = List(3, 56, 1, 4, 72)
scala> // map()參數是一個函數
scala> myList.map((x) => 2*x)
res15: List[Int] = List(6, 112, 2, 8, 144)
scala> //嘗試給map()函提供一個方法做爲參數
scala> def m4(x:Int) = 3*x
m4: (x: Int)Int
scala> //正常執行
scala> myList.map(m4)
res17: List[Int] = List(9, 168, 3, 12, 216)
這是由於,若是指望出現函數的地方咱們提供了一個方法的話,該方法就會自動被轉換成函數。該行爲被稱爲ETA expansion。
這樣的話使用函數將會變得簡單不少。你能夠按照下面的代碼驗證該行爲:
scala> //指望出現函數的地方,咱們可使用方法
scala> val f3:(Int)=>Int = m4
f3: Int => Int = <function1>
scala> //不指望出現函數的地方,方法並不會自動轉換成函數
scala> val v3 = m4
<console>:8: error: missing arguments for method m4;
follow this method with `_‘ if you want to treat it as a partially applied function
val v3 = m4
^
利用這種自動轉換,咱們能夠寫出很簡潔的代碼,以下面這樣
scala> //10.<被解釋成obj.method,即整形的<的方法,因此該表達式是一個方法,會被解釋成函數
scala> myList.filter(10.<)
res18: List[Int] = List(56, 72)
由於在scala中操做符被解釋稱方法
前綴操做符:op obj 被解釋稱obj.op
中綴操做符:obj1 op obj2被解釋稱obj1.op(obj2)
後綴操做符:obj op被解釋稱obj.op
你能夠寫成10<而不是10.<
scala> myList.filter(10<)
warning: there were 1 feature warning(s); re-run with -feature for details
res19: List[Int] = List(56, 72)
如何強制把一個方法變成函數
能夠在方法名後面加一個下劃線強制變成函數,部分應用函數
scala> val f4 = m4 _
f4: Int => Int = <function1>
scala> f4(2)
res20: Int = 6
傳名參數是一個方法
傳名參數實質是一個沒有參數列表的方法。正是所以你纔可使用名字調用而不用添加()
scala> //使用兩次‘x‘,意味着進行了兩次方法調用
scala> def m1(x: => Int)=List(x,x)
m1: (x: => Int)List[Int]
scala> import util.Random
import util.Random
scala> val r = new Random()
r: scala.util.Random = scala.util.Random@d4c330b
scala> //由於方法被調用了兩次,因此兩個值不相等
scala> m1(r.nextInt)
res21: List[Int] = List(-1273601135, 2004676878)
若是你在方法體部分緩存了傳名參數(函數),那麼你就緩存了值(由於x函數被調用了一次)
scala> //把傳名參數表明的函數緩存起來
scala> def m1(x: => Int) ={val y=x;List(y,y)}
m1: (x: => Int)List[Int]
scala> m1(r.nextInt)
res22: List[Int] = List(-1040711922, -1040711922)
可否在函數體部分引用傳名參數所表明的方法呢,是能夠的(緩存的是傳名參數所表明的方法)。
scala> def m1(x: => Int)={val y=x _;List(y(),y())}
m1: (x: => Int)List[Int]
scala> m1(r.nextInt)
res23: List[Int] = List(-1982925840, -933815401)