Scala學(xué)習(xí)筆記(六) Scala的偏函數(shù)和偏應(yīng)用函數(shù)

1. 偏函數(shù)

偏函數(shù)(Partial Function),是一個(gè)數(shù)學(xué)概念它不是"函數(shù)"的一種, 它跟函數(shù)是平行的概念。
Scala中的Partia Function是一個(gè)Trait,其的類型為PartialFunction[A,B],其中接收一個(gè)類型為A的參數(shù),返回一個(gè)類型為B的結(jié)果。

舉個(gè)例子


scala> val pf:PartialFunction[Int,String] = {
     |   case 1=>"One"
     |   case 2=>"Two"
     |   case 3=>"Three"
     |   case _=>"Other"
     | }
pf: PartialFunction[Int,String] = <function1>

scala> pf(1)
res0: String = One

scala> pf(2)
res1: String = Two

scala> pf(3)
res2: String = Three

scala> pf(4)
res3: String = Other

偏函數(shù)內(nèi)部有一些方法,比如isDefinedAt、OrElse、 andThen、applyOrElse等等。

1.1 isDefinedAt

isDefinedAt : 這個(gè)函數(shù)的作用是判斷傳入來的參數(shù)是否在這個(gè)偏函數(shù)所處理的范圍內(nèi)。
剛才定義的pf來嘗試使用isDefinedAt(),只要是數(shù)字都是正確的,因?yàn)橛衏ase _=>"Other"這一句。如果換成其他類型就會(huì)報(bào)錯(cuò)。

scala> pf.isDefinedAt(1)
res4: Boolean = true

scala> pf.isDefinedAt(2)
res5: Boolean = true

scala> pf.isDefinedAt("1")
<console>:13: error: type mismatch;
 found   : String("1")
 required: Int
       pf.isDefinedAt("1")
                      ^

scala> pf.isDefinedAt(100)
res7: Boolean = true

那我們再定義一個(gè)PartialFunction

scala> val anotherPF:PartialFunction[Int,String] = {
     |    case 1=>"One"
     |    case 2=>"Two"
     |    case 3=>"Three"
     | }
anotherPF: PartialFunction[Int,String] = <function1>

scala> anotherPF.isDefinedAt(1)
res8: Boolean = true

scala> anotherPF.isDefinedAt(2)
res9: Boolean = true

scala> anotherPF.isDefinedAt(3)
res10: Boolean = true

scala> anotherPF.isDefinedAt(4)
res11: Boolean = false

去掉了原先的最后一句,再執(zhí)行anotherPF.isDefinedAt(4)會(huì)返回false。

1.2 orElse

orElse : 將多個(gè)偏函數(shù)組合起來使用,效果類似case語句。


scala> val onePF:PartialFunction[Int,String] = {
     |   case 1=>"One"
     | }
onePF: PartialFunction[Int,String] = <function1>

scala> val twoPF:PartialFunction[Int,String] = {
     |   case 2=>"Two"
     | }
twoPF: PartialFunction[Int,String] = <function1>

scala> val threePF:PartialFunction[Int,String] = {
     |   case 3=>"Three"
     | }
threePF: PartialFunction[Int,String] = <function1>

scala> val otherPF:PartialFunction[Int,String] = {
     |   case _=>"Other"
     | }
otherPF: PartialFunction[Int,String] = <function1>

scala> val newPF = onePF orElse twoPF orElse threePF orElse otherPF
newPF: PartialFunction[Int,String] = <function1>

scala> newPF(1)
res0: String = One

scala> newPF(2)
res1: String = Two

scala> newPF(3)
res2: String = Three

scala> newPF(4)
res3: String = Other

這樣,newPF跟原先的pf效果是一樣的。

1.3 andThen

andThen: 相當(dāng)于方法的連續(xù)調(diào)用,比如g(f(x))。

scala> val pf1:PartialFunction[Int,String] = {
     |   case i if i == 1 => "One"
     | }
pf1: PartialFunction[Int,String] = <function1>

scala> val pf2:PartialFunction[String,String] = {
     |   case str if str eq "One" => "The num is 1"
     | }
pf2: PartialFunction[String,String] = <function1>

scala> val num = pf1 andThen pf2
num: PartialFunction[Int,String] = <function1>

scala> num(1)
res4: String = The num is 1

pf1的結(jié)果返回類型必須和pf2的參數(shù)傳入類型必須一致,否則會(huì)報(bào)錯(cuò)。

1.4 applyOrElse

applyOrElse:它接收2個(gè)參數(shù),第一個(gè)是調(diào)用的參數(shù),第二個(gè)是個(gè)回調(diào)函數(shù)。如果第一個(gè)調(diào)用的參數(shù)匹配,返回匹配的值,否則調(diào)用回調(diào)函數(shù)。

scala> onePF.applyOrElse(1,{num:Int=>"two"})
res5: String = One

scala> onePF.applyOrElse(2,{num:Int=>"two"})
res6: String = two

在這個(gè)例子中,第一次onePF匹配了1成功則返回的是"One"字符串。第二次onePF匹配2失敗則觸發(fā)回調(diào)函數(shù),返回的是"Two"字符串。

2. 偏應(yīng)用函數(shù)

偏應(yīng)用函數(shù)(Partial Applied Function)也叫部分應(yīng)用函數(shù),跟偏函數(shù)(Partial Function)從英文名來看只有一字之差,但他們二者之間卻有天壤之別。

部分應(yīng)用函數(shù), 是指一個(gè)函數(shù)有n個(gè)參數(shù), 而我們?yōu)槠涮峁┥儆趎個(gè)參數(shù), 那就得到了一個(gè)部分應(yīng)用函數(shù)。
個(gè)人理解的偏應(yīng)用函數(shù)類似于柯里化,可以參考我以前寫的文章借助Java 8實(shí)現(xiàn)柯里化

舉個(gè)例子,定義好一個(gè)函數(shù)有3個(gè)參數(shù),再提供幾個(gè)有1-2個(gè)已知參數(shù)的偏應(yīng)用函數(shù)

scala> def add(x:Int,y:Int,z:Int) = x+y+z
add: (x: Int, y: Int, z: Int)Int

scala> def addX = add(1,_:Int,_:Int) // x 已知
addX: (Int, Int) => Int

scala> addX(2,3)
res1: Int = 6

scala> addX(3,4)
res2: Int = 8

scala> def addXAndY = add(10,100,_:Int) // x 和 y 已知
addXAndY: Int => Int

scala> addXAndY(1)
res3: Int = 111

scala> def addZ = add(_:Int,_:Int,10) // z 已知
addZ: (Int, Int) => Int

scala> addZ(1,2)
res4: Int = 13

總結(jié)

本篇筆記是為了下一篇 Scala 模式匹配所做的鋪墊。模式匹配會(huì)用到偏函數(shù),所以先整理出來。還詳細(xì)介紹了偏函數(shù)和偏應(yīng)用函數(shù)的區(qū)別。

先前的文章:
Scala學(xué)習(xí)筆記(五) 抽象類以及類中的一些語法糖
Scala學(xué)習(xí)筆記(四) 類的初步
Scala學(xué)習(xí)筆記(三)
Scala學(xué)習(xí)筆記(二)
Scala學(xué)習(xí)筆記(一)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容