Scala入門之部分應用函數與偏函數

1.部分應用函數

部分應用函數(Partial Applied Function)是指缺少部分參數的函數.
package com.dt.scala.moguyun

/**
  * 部分應用函數
  * Created by Administrator on 2016/8/10.
  */
object PartialAppliedFunctionLearn {
  def main(args: Array[String]) {
    //第一種常見樣式
    val result = sum _ //表明是一個部分應用函數,參數一個都沒定
    val r = result(2)(3)(4)
    println(r)
    val r1 = result(1)//返回一個function1
    println(r1)
    val r2 = result(2)(_: Int)(4)
    println(r2)//返回一個function1
    val r3 = r2(5)//完整
    println(r3)

    //第二種常見樣式
    val s = sum(4)(8)(_: Int)//注意這裏得用_通配符,用i,j等不可以
    val s1 = s(7)
    println(s1)

    val s2 = sum(5)(_: Int)(_: Int)//返回一個function2
    println(s2)
    val s3 = s2(5, 3) //注意這裏傳入一個(Int, Int),而不是這樣(5)(3)
    println(s3)
  }

  /**
    * 定義一個函數,要求傳入三個Int類型參數
    */
  def sum(i: Int)(j: Int)(k: Int): Int ={
    i + j + k
  }
}

結果如下:

9
<function1>
<function1>
11
19
<function2>
13

2.偏函數

偏函數是隻對函數定義域的一個子集進行定義的函數。這知識點是難點,自己也沒能很好理解怎麼用,什麼時候用 -_-!
記得學線程的時候有個receive和react ,當時老師說這個是偏函數,也沒懂什麼意思。看源碼
    def receive[R](f : scala.PartialFunction[scala.Any, R]) : R = { /* compiled code */ }
    override def react(handler : scala.PartialFunction[scala.Any, scala.Unit]) : scala.Nothing = 
這裏的參數都是scala.PartialFunction類型的,泛型參數裏第一個表示輸入的類型,第二個表示輸出的類型。
其實在下面代碼中
class HelloActor extends Actor{
  override def act(): Unit = {
    while (true) {
      //receive從郵箱中獲取一條消息
      //然後傳遞給它的參數
      //該參數是一個偏函數
      receive {
        case "actorDemo" => println("receive....ActorDemo")
      }
    }
  }
}

這裏寫圖片描述
可以從上面圖片中看出receive的參數是一個偏函數,輸入參數是”actorDemo”,輸出參數是Unit.可以理解case就是一個函數,經常有好多組case,如果一組case語句沒有涵蓋所有的情況,那麼這組case語句就可以被看做是一個偏函數。
按我的理解,偏函數直接使用時像模式匹配,而偏函數作爲參數傳入時就難理解,更難應用。(以後再學怎麼用),下面是自己寫的代碼,當作認識偏函數

package com.dt.scala.moguyun

/**
  * 偏函數
  * Created by hlf on 2016/8/10.
  */
object PartialFunctionLearn {
  def main(args: Array[String]): Unit = {
    jump("hello")
    //    jump(5)不是String直接報錯
    //因爲加了其餘情況時會輸出,如果不加其餘情況的匹配會報錯:
    //Exception in thread "main" scala.MatchErro
    jump("love")

    println(run(5))

    //定義時也可以用val來定義
    val jump2: PartialFunction[String, Unit] = {
      case "hello" => println("fine, and you?")
      case "have a good day!" => println("the same to you!")
      //    case 5 => println("why get me a Five?")
      case _ => println("what is this? get away from me!")
    }

    jump2("have a good day!")


  }

  /**
    * 定義一個偏函數,有兩種方式定義偏函數,下面這種更好,
    * 因爲有isDefinedAt方法來校驗參數是否會得到處理.
    * 或者在調用時使用一個orElse方法,該方法接受另一個偏函數,
    * 用來定義當參數未被偏函數捕獲時該怎麼做
    */
  def jump: PartialFunction[String, Unit] = {
    case "hello" => println("fine, and you?")
    case "have a good day!" => println("the same to you!")
    //    case 5 => println("why get me a Five?")
    case _ => println("what is this? get away from me!")//註釋的話如果匹配不上會報錯
  }


  /**
    * 另一種定義一個偏函數的方式,不細說
    */
  def run = (x: Int) => x match {
    case x if x > 1 => 1
  }


}
結果
fine, and you?
what is this? get away from me!
1
the same to you!

什麼時候該使用偏函數?
當我們確定我們的程序不會被傳入不可處理的值時,我們就可以使用偏函數。這樣萬一程序被傳入了不應該被傳入的值,程序自動拋出異常,而不需要我們手工編寫代碼去拋出異常,減少了我們的代碼量。(不全)

3.蘑茹雲代碼

package com.dt.spark.scala.bascis

object HelloPartionalFunction {
  def main(args: Array[String]): Unit = {
    val sample =1 to 10
    val isEven:PartialFunction[Int,String]={
      case x if x % 2 == 0 =>   x + "is even" 
        }
    isEven(4)
    val evenNumbers = sample collect isEven
    evenNumbers.foreach { println }
     val isOdd:PartialFunction[Int,String]={
      case x if x % 2 == 1 =>   x + "is Odd" 
        }

     val numbers =sample map {isEven orElse isOdd}
     numbers.foreach { println }
  }
}





2is even
4is even
6is even
8is even
10is even
1is Odd
2is even
3is Odd
4is even
5is Odd
6is even
7is Odd
8is even
9is Odd
10is even

以上蘑茹雲代碼來自[DT大數據夢工廠]首席專家Spark專家王家林老師的課程分享。感謝王老師的分享,更多精彩內容請掃描關注[DT大數據夢工廠]微信公衆號DT_Spark

發佈了45 篇原創文章 · 獲贊 5 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章