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í)筆記(一)