如果你想定義一個函數,而讓它只接受和處理其參數定義域范圍內的子集,對於這個參數范圍外的參數則拋出異常,這樣的函數就是偏函數(顧名思異就是這個函數只處理傳入來的部分參數)。
偏函數是個特質其的類型為PartialFunction[A,B],其中接收一個類型為A的參數,返回一個類型為B的結果。
其有個重要的函數就是:
def isDefinedAt(x: A): Boolean //作用是判斷傳入來的參數是否在這個偏函數所處理的范圍內
定義一個普通的除法函數:
scala> val divide = (x : Int) => 100/x divide: Int => Int = <function1> 輸入參數0 scala> divide(0) java.lang.ArithmeticException: / by zero
顯然,當我們將0作為參數傳入時會報錯,一般的解決辦法就是使用try/catch來捕捉異常或者對參數進行判斷看其是否等於0;但是在Scala的偏函數中這些都已經封裝好了,如下:將divide定義成一個偏函數()
val divide = new PartialFunction[Int,Int] { def isDefinedAt(x: Int): Boolean = x != 0 //判斷x是否等於0,當x = 0時拋出異常 def apply(x: Int): Int = 100/x }
但是,當偏函數與case語句結合起來就能使代碼更簡潔,如下:
val divide1 : PartialFunction[Int,Int] = { case d : Int if d != 0 => 100/d //功能和上面的代碼一樣,這就是偏函數的強大之處,方便,簡潔!! }
其實這代碼就是對上面那段代碼的封裝,這里同樣調用isDefinedAt方法
scala> divide1.isDefinedAt(0) res1: Boolean = false scala> divide1.isDefinedAt(10) res2: Boolean = true
再舉個與case結合使用的例子:
val rs : PartialFunction[Int , String] = { case 1 => "One" case 2 => "Two" case _ => "Other" }
輸入:
scala> rs(1) res4: String = One scala> rs(2) res5: String = Two scala> rs(100) res6: String = Other
OrElse
OrElse方法可以將多個偏函數組合起來使用,結合起來的效果類似case語句,但是每個偏函數里又可以再使用case
scala> val or1 : PartialFunction[Int,String] = {case 1 => "One"} or1: PartialFunction[Int,String] = <function1> scala> val or2 : PartialFunction[Int,String] = {case 2 => "Two"} or2: PartialFunction[Int,String] = <function1> scala> val or_ : PartialFunction[Int,String] = {case _ => "Other"} or_: PartialFunction[Int,String] = <function1> scala> val or = or1 orElse or2 orElse or_ //使用orElse將多個偏結合起來 or: PartialFunction[Int,String] = <function1> scala> or(1) res7: String = One scala> or(20) res9: String = Other
orElse還可以直接連接case使用
scala> val orCase:(Int => String) = or1 orElse {case _ => "Other"} orCase: Int => String = <function1> scala> orCase(1) res10: String = One scala> orCase(10) res11: String = Other
andThen
對函數的結果進行下一步的處理
scala> val at1 : PartialFunction[Int,String] = {case cs if cs == 1 => "One"} at1: PartialFunction[Int,String] = <function1> scala> val at2 : PartialFunction[String,String] = {case cs if cs eq "One" => "The num is 1"} at2: PartialFunction[String,String] = <function1> scala> val num = at1 andThen at2 num: PartialFunction[Int,String] = <function1> scala> num(1) res18: String = The num is 1
注意:at1函數的結果返回類型必須和at2函數的參數傳入類型一致,不然會編譯報錯