溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Scala的偏應用函數(shù)是什么

發(fā)布時間:2021-07-15 09:40:53 來源:億速云 閱讀:131 作者:chen 欄目:編程語言

這篇文章主要講解了“Scala的偏應用函數(shù)是什么”,文中的講解內(nèi)容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“Scala的偏應用函數(shù)是什么”吧!

盡管前面的例子里下劃線替代的只是單個參數(shù),你還可以使用一個下劃線替換整個參數(shù)列表。例如,寫成println(_),或者更好的方法你還可以寫成println _。下面是一個例子:

someNumbers.foreach(println _)

51CTO編輯推薦:Scala編程語言專題

Scala把這種短格式直接看作是你輸入了下列代碼:

someNumbers.foreach(x => println(x))

因此,這個例子中的下劃線不是單個參數(shù)的占位符。它是整個參數(shù)列表的占位符。請記住要在函數(shù)名和下劃線之間留一個空格,因為不這樣做編譯器會認為你是在說明一個不同的符號,比方說是,似乎不存在的名為println_的方法。

以這種方式使用下劃線時,你就正在寫一個偏應用函數(shù):partially applied function。Scala里,當你調(diào)用函數(shù),傳入任何需要的參數(shù),你就是在把函數(shù)應用到參數(shù)上。如,給定下列函數(shù):

scala> def sum(a: Int, b: Int, c: Int) = a + b + c  sum: (Int,Int,Int)Int

你就可以把函數(shù)sum應用到參數(shù)1,2和3上,如下:

scala> sum(1, 2, 3)  res12: Int = 6

偏應用函數(shù)是一種表達式,你不需要提供函數(shù)需要的所有參數(shù)。代之以僅提供部分,或不提供所需參數(shù)。比如,要創(chuàng)建不提供任何三個所需參數(shù)的調(diào)用sum的偏應用表達式,只要在“sum”之后放一個下劃線即可。然后可以把得到的函數(shù)存入變量。舉例如下:

scala> val a = sum _  a: (Int, Int, Int) => Int = < function>

有了這個代碼,Scala編譯器以偏應用函數(shù)表達式,sum _,實例化一個帶三個缺失整數(shù)參數(shù)的函數(shù)值,并把這個新的函數(shù)值的索引賦給變量a。當你把這個新函數(shù)值應用于三個參數(shù)之上時,它就轉回頭調(diào)用sum,并傳入這三個參數(shù):

scala> a(1, 2, 3)  res13: Int = 6

實際發(fā)生的事情是這樣的:名為a的變量指向一個函數(shù)值對象。這個函數(shù)值是由Scala編譯器依照偏應用函數(shù)表達式sum _,自動產(chǎn)生的類的一個實例。編譯器產(chǎn)生的類有一個apply方法帶三個參數(shù)。產(chǎn)生的類擴展了特質Function3,定義了三個參數(shù)的apply方法。之所以帶三個參數(shù)是因為sum _表達式缺少的參數(shù)數(shù)量為三。Scala編譯器把表達式a(1,2,3)翻譯成對函數(shù)值的apply方法的調(diào)用,傳入三個參數(shù)1,2,3。因此a(1,2,3)是下列代碼的短格式:

scala> a.apply(1, 2, 3)  res14: Int = 6

Scala編譯器根據(jù)表達式sum _自動產(chǎn)生的類里的apply方法,簡單地把這三個缺失的參數(shù)前轉到sum,并返回結果。本例中apply調(diào)用了sum(1,2,3),并返回sum返回的,6。

這種一個下劃線代表全部參數(shù)列表的表達式的另一種用途,就是把它當作轉換def為函數(shù)值的方式。例如,如果你有一個本地函數(shù),如sum(a: Int, b: Int, c: Int): Int,你可以把它“包裝”在apply方法具有同樣的參數(shù)列表和結果類型的函數(shù)值中。當你把這個函數(shù)值應用到某些參數(shù)上時,它依次把sum應用到同樣的參數(shù),并返回結果。盡管不能把方法或嵌套函數(shù)賦值給變量,或當作參數(shù)傳遞給其它方法,但是如果你把方法或嵌套函數(shù)通過在名稱后面加一個下劃線的方式包裝在函數(shù)值中,就可以做到了。

現(xiàn)在,盡管sum _確實是一個偏應用函數(shù),或許對你來說為什么這么稱呼并不是很明顯。這個名字源自于函數(shù)未被應用于它所有的參數(shù)。在sum _的例子里,它沒有應用于任何參數(shù)。不過還可以通過提供某些但不是全部需要的參數(shù)表達一個偏應用函數(shù)。舉例如下:

scala> val b = sum(1, _: Int, 3)  b: (Int) => Int = < function>

這個例子里,你提供了***個和***一個參數(shù)給sum,但中間參數(shù)缺失。因為僅有一個參數(shù)缺失,Scala編譯器會產(chǎn)生一個新的函數(shù)類,其apply方法帶一個參數(shù)。在使用一個參數(shù)調(diào)用的時候,這個產(chǎn)生的函數(shù)的apply方法調(diào)用sum,傳入1,傳遞給函數(shù)的參數(shù),還有3。如下:

scala> b(2)  res15: Int = 6

這個例子里,b.apply調(diào)用了sum(1,2,3)。

scala> b(5)  res16: Int = 9

這個例子里,b.apply調(diào)用了sum(1,5,3)。

如果你正在寫一個省略所有參數(shù)的偏應用程序表達式,如println _或sum _,而且在代碼的那個地方正需要一個函數(shù),你可以去掉下劃線從而表達得更簡明。例如,代之以打印輸出someNumbers里的每一個數(shù)字(定義在第113頁)的這種寫法:

someNumbers.foreach(println _)

你可以只是寫成:

someNumbers.foreach(println)

***一種格式僅在需要寫函數(shù)的地方,如例子中的foreach調(diào)用,才能使用。編譯器知道這種情況需要一個函數(shù),因為foreach需要一個函數(shù)作為參數(shù)傳入。在不需要函數(shù)的情況下,嘗試使用這種格式將引發(fā)一個編譯錯誤。舉例如下:

scala> val c = sum  < console>:5: error: missing arguments for method sum...  follow this method with `_' if you want to treat it as   a partially applied function   val c = sum   ?  scala> val d = sum _  d: (Int, Int, Int) => Int = < function>  scala> d(10, 20, 30)  res17: Int = 60

為什么要使用尾下劃線?

Scala的偏應用函數(shù)語法凸顯了Scala與經(jīng)典函數(shù)式語言如Haskell或ML之間,設計折中的差異。在經(jīng)典函數(shù)式語言中,偏應用函數(shù)被當作普通的例子。更進一步,這些語言擁有非常嚴格的靜態(tài)類型系統(tǒng)能夠暴露出你在偏應用中可能犯的所有錯誤。Scala與指令式語言如Java關系近得多,在這些語言中沒有應用所有參數(shù)的方法會被認為是錯誤的。進一步說,子類型推斷的面向對象的傳統(tǒng)和全局的根類型接受一些被經(jīng)典函數(shù)式語言認為是錯誤的程序。

舉例來說,如果你誤以為List的drop(n: Int)方法如tail(),那么你會忘記你需要傳遞給drop一個數(shù)字。你或許會寫,“println(drop)”。如果Scala采用偏應用函數(shù)在哪兒都OK的經(jīng)典函數(shù)式傳統(tǒng),這個代碼就將通過類型檢查。然而,你會驚奇地發(fā)現(xiàn)這個println語句打印的輸出將總是< function>!可能發(fā)生的事情是表達式drop將被看作是函數(shù)對象。因為println可以帶任何類型對象,這個代碼可以編譯通過,但產(chǎn)生出乎意料的結果。

為了避免這樣的情況,Scala需要你指定顯示省略的函數(shù)參數(shù),盡管標志簡單到僅用一個‘_’。Scala允許你僅在需要函數(shù)類型的地方才能省略這個僅用的_。

感謝各位的閱讀,以上就是“Scala的偏應用函數(shù)是什么”的內(nèi)容了,經(jīng)過本文的學習后,相信大家對Scala的偏應用函數(shù)是什么這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權內(nèi)容。

AI