Scala語言為了讓函數字面量更加精簡,還可以使用下划線作為占位符,用來表示一個或多個參數。
我們用來表示的參數必須滿足只在函數字面量中出現一次。
我們用例子來看占位符的用法
scala> val list = List(1,2,3,4,5) list: List[Int] = List(1, 2, 3, 4, 5) scala> list.filter( _ > 3 )//等同於 x => x > 3 res0: List[Int] = List(4, 5)
我們看到 _ 就好像是表達式中需要被填入的空,函數每次調用的時候這個空就被一個傳入參數填上
但是參數是依次填入的,不能重復。也就是說,像上例的 1,2,3,4,5.並不能從頭再來依次。
scala> val nums = List(1,2,3,4,5) nums: List[Int] = List(1, 2, 3, 4, 5) scala> nums.map((_,1)) //等同於 x => (x,1) res1: List[(Int, Int)] = List((1,1), (2,1), (3,1), (4,1), (5,1))
當然,我們也可以使用多個占位符來表示多個參數。
scala> val nums = List(1,2,3,4,5) nums: List[Int] = List(1, 2, 3, 4, 5) scala> nums.reduce( _+_ ) //相當於 a + b res2: Int = 15
上例中,第一個占位符代表一個參數,第二個代表不同於第一個的參數。
執行過程是這樣的,先第一個參數 1 填上第一個占位符,第二個參數 2 填入第二個占位符,注意這里並不是參數列表從新填一次。
執行1+2 = 3.因為reduce,3重新排入list中,list現在為3,3,4,5
然后再次填入,3 + 3,list中變為 6,4,5
依次類推。結果為 15.
但是注意,我們在使用占位符的時候,編譯器可能並沒有足夠的信息區推斷你缺失的類型
使用的時候不要盲目的省略,避免造成不必要的錯誤。
scala> val f = _ + _ <console>:11: error: missing parameter type for expanded function ((x$1: <error>, x$2) => x$1.$plus(x$2)) val f = _ + _ ^ <console>:11: error: missing parameter type for expanded function ((x$1: <error>, x$2: <error>) => x$1.$plus(x$2)) val f = _ + _ ^
上面的例子就是,我們在定義 f 方法的時候只用了占位符來表示兩個參數,但是編譯器並不能推斷出你的參數類型,報錯。
這個時候我們需要注明參數類型
scala> val f = (_:Int) + (_:Int) f: (Int, Int) => Int = $$Lambda$1108/2058316797@4a8bf1dc scala> f(1,2) res5: Int = 3
為什么我們開始的例子不用注明參數類型呢?因為我們在創建List的時候指明了類型為List[Int] 也就是編譯器知道每個參數都為Int
注意,當使用多個占位符的時候,代表的是不同的參數,不能是相同的參數。
占位符也可以代替一個參數列表
scala> def sum(a:Int,b:Int,c:Int) = a+b+c sum: (a: Int, b: Int, c: Int)Int scala> val a = sum _ a: (Int, Int, Int) => Int = $$Lambda$1137/810864083@755a4ef5
我們這里用了一個占位符代替了sum方法的參數列表,注意方法和占位符之間要有個空格,因為scala語言中方法名可以定義這樣:sum_ 。
我們在創建方法的時候並不能用占位符來代替參數列表,編譯器並不能推斷出占位符代表的東西。
只能用占位符來代替已經明確的東西,也就是說來代替已經定義好的方法的參數列表。
scala> val b = sum(1,_:Int,3) b: Int => Int = $$Lambda$1138/1122185195@3652dd19 scala> b(2) res6: Int = 6
我們還可以這么用,用占位符來代替其中的一個參數,然后調用的時候只需要傳入一個參數即可。
注意,這里代替的時候輸出初始化一個參數,必須要表明參數類型。
當然有的時候我們還可以更省略,不過只能用在明確需要函數的時候。
scala> list.foreach(println _) 1 2 3 4 5 scala> list.foreach(println) 1 2 3 4 5