溫馨提示×

溫馨提示×

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

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

Scala的函數(shù)式編程

發(fā)布時間:2020-06-15 11:30:56 來源:網(wǎng)絡(luò) 閱讀:449 作者:原生zzy 欄目:開發(fā)技術(shù)

Scala的函數(shù)式編程

  Scala的函數(shù)式編程的特點

   - 高階函數(shù)
   - 閉包
   - 模式匹配 可參考:https://blog.51cto.com/14048416/2337136
   - 單一賦值
   - 延遲計算
   - 類型推導(dǎo)
   - 尾部調(diào)用優(yōu)化
   - 隱式轉(zhuǎn)化
  這篇博文重點介紹:高階函數(shù)、閉包、隱式轉(zhuǎn)化。

1. 高階函數(shù)

   高階函數(shù)主要有兩種:將一個函數(shù)當(dāng)做另外一個函數(shù)的參數(shù)返回值是函數(shù)的函數(shù)。

  • 高階函數(shù)的定義

    object Test01 {
    def main(args: Array[String]): Unit = {
    
    }
    //1.函數(shù)作為參數(shù)
    def sum1(f:(Int,Int)=>Int,x:Int,y:Int):Int ={
      f(x,y)
    }
    //2.函數(shù)作為返回值
    def sum2(x:Int)={
    (y:Int)=>x+y
    }
    
    //3.柯里化寫法
    def sum3(f:(Int,Int))(x:Int,y:Int) = f(x,y)
    
    //4.使用隱式轉(zhuǎn)換的方式,傳入默認(rèn)值
    def sum4(x:Int)(implicit  y:Int=10) =x+y
    }
  • 函數(shù)的調(diào)用

    object Test01 {
    def main(args: Array[String]): Unit = {
    //1.普通函數(shù)傳參
    def func1(x:Int,y:Int) = x+y
    println(func1(1,2))
    
    //2.高階函數(shù)傳參以返回值是函數(shù)為例)
    def func2(x:Int) = (y:Int) => x+y
    //method one
    val func22=func2(2)
    println(func22(1))
    //method two
    println(func2(1)(2))
    
    //3.高階函數(shù)改寫成柯里化方式傳入?yún)?shù)
    def func3(x:Int)(y:Int) = x+y
    //method one
    val func33=func3(3) _
    println(func33(2))
    //method two
    println(func3(5)(6))
    
    //4.有默認(rèn)值時的調(diào)用
    def func4(x:Int)(y:Int =10) = y+x
    //method one 調(diào)用時,必須使用()()
    println(func4(5)())
    //method two
    println(func4(5)(5))
    
    //5.使用隱式參數(shù)在有默認(rèn)值時的調(diào)用
    def func5(x:Int)( implicit y:Int =10) = y+x
    //method one 調(diào)用時,必須使用()()
    println(func5(5)())
    //method two
    println(func5(5)(5))
    }
    }
  • 關(guān)于方法中的隱式參數(shù)
    在聲明方法時,有某個參數(shù)使用了implicit修飾,并附加了默認(rèn)值。

    object Test01 {
    def main(args: Array[String]): Unit = {
    //聲明一個有implicit修飾的參數(shù)的方法
    def sum(x:Int)(implicit  y:Int=10) =x+y
    
    //1.碼運行的全局環(huán)境中不存在一個同類型的隱式變量,而且調(diào)用的時候,也沒有參入?yún)?shù)
    println(sum(5))  //結(jié)果打?。?5
    
    //2.如果全局環(huán)境中,存在一個同類型的隱式變量
    implicit  val num:Int=6
    println(sum(5))  //結(jié)果打?。?1 ,這個全局的隱式變量值會替換方法定義中指定
    
    //3.忽略所有的隱式變量值,可以由用戶直接傳入新的參數(shù)
    println(sum(5)(5))  //結(jié)果打?。?0
    }
    }

    注意:如果全局出現(xiàn)了多個同類型的隱式參數(shù):

    implicit val abc:Int =6
    implicit val aaa:Int =6
    def sum(x:Int)(implicit y:Int =5) = x+y
    println(sum(5))

    此時這個段代碼會報錯:Error:(80, 16) ambiguous implicit values,所以,如果在方法中定義了隱式的參數(shù),那么在全局變量中只能有一個與方法中類型相同的隱式變量。
    隱式參數(shù)的總結(jié)
      - 隱式轉(zhuǎn)換會首先從全局中尋找,尋找不到,才使用隱式參數(shù)
      - 如果隱式參數(shù)存在二義性,那么程序就報錯

  • 高階函數(shù)的總結(jié)
      - 函數(shù)是 Scala 中的頭等公民
      - 函數(shù)可以作為方法的參數(shù)
      - 函數(shù)可以作為方法的返回值
      - 方法也可以被轉(zhuǎn)換成函數(shù),特定的場景下使用”“ 進行轉(zhuǎn)化即可

2. 閉包

 閉包是一個函數(shù),返回值依賴與聲明在函數(shù)外部的一個或者多個變量。
 閉包通常來講可以簡單的認(rèn)為是可以訪問一個函數(shù)里面局部變量的另一個函數(shù)。
例:

object Test01 {
  def main(args: Array[String]): Unit = {
    //定義一個閉包函數(shù)
    def bibao() ={
      var num:Int=0
      //在閉包函數(shù)中定義一個函數(shù),用于修改變量num的值
      val add=(x:Int)=>{
        num+=x
        num
      }
      //最終將這個函數(shù)返回
      add
    }
    val result=bibao()
    println(result(1))  //1
    println(result(2))  //3
    println(result(3))  //6
  }
}

 通過上面的案例我們了解到:每一次在調(diào)用result實際上是調(diào)用bibao方法中的add函數(shù),然后對bibao方法中的num變量進行疊加,實現(xiàn)了使用另一個函數(shù),訪問其他方法中的局部變量的功能,這個就是閉包。當(dāng)bibao調(diào)用的時候,就會申請一塊內(nèi)存區(qū)間,存儲了add和num變量,bibao這個函數(shù)當(dāng)被調(diào)用的時候,就返回了內(nèi)存的一個函數(shù)add,調(diào)用的時候,result(1),相當(dāng)于add(2),num的值就會被返回。當(dāng)然如果重新調(diào)用一次bibao方法,這個num變量會被重新初始化。
閉包的弊端 : 在一個線程中,或者一個程序中,不能太多的定義這樣的閉包函數(shù),定義閉包函數(shù)時,其中的局部變量一定不能太大。因為閉包中的局部變量時常駐內(nèi)存的,一旦定義之后,就一直在內(nèi)存中,除非程序終止。

3. 隱式轉(zhuǎn)化

scala的神奇之處:之前有過1 to 10 其實可以寫成 1.to(10),那其實就是表示:1 是一個 Int 類型的變量,所以證明 Int 類中會有一個 to 的方法,但事實上,我們在 Int 類型中根本就沒有尋找 to 方法,那也就是說對一個 Int 類型的變量 1 調(diào)用 Int 類型不存在的一個方法,這怎么還能正常運行 呢? 隱式轉(zhuǎn)換
dome01:

object Test01 {
  def main(args: Array[String]): Unit = {
    //定義一個傳入兩個Int類型的方法
    def m1(x:Int,y:Int):Int ={
      x+y
    }
    //定義一個Double的轉(zhuǎn)換成 Int類型 方法,隱式轉(zhuǎn)化引入這個方法
    implicit def m2(x:Double) = x.toInt

  //調(diào)用m1,并傳入double類型的值
    println(m1(3.5,2.6)) //沒有報錯,正常打印
  }
}

dome02:
Scala的函數(shù)式編程

  • 隱式轉(zhuǎn)換的種類
      在方法傳入值的時候,如果定義的參數(shù)和傳入的參數(shù)類型不同,使用隱式轉(zhuǎn)化。
    def m1(x:Int,y:Int):Int ={
    x+y
    }
    implicit  def m2(x:Double) = x.toInt
    println(m1(2.0,3.2))

      當(dāng)一個類沒有某個方法的時候,但是此時調(diào)用這個方法,使用隱式轉(zhuǎn)換
    以1.to(5)這個為例,1是一個int類型,但是Int中沒有定義to方法,但是richInt中定義了to方法調(diào)用了:1 to 10,其實是調(diào)用了:1.to(10),但是:Int 中沒有 to 方法,所以:去尋找引入的隱式轉(zhuǎn)換中有沒有能把 Int 類型轉(zhuǎn)換成能執(zhí)行 to 方法的類型,果然:在系統(tǒng)引入的轉(zhuǎn)換中發(fā)現(xiàn):implicit def intWrapper(x: Int): runtime.RichInt,所以:最終 int 類型的 1 就被轉(zhuǎn)換成了 RichInt 類型的變量

  • 隱式轉(zhuǎn)換的時機
    當(dāng)調(diào)用某個對象不存在的方法時
    object Test01 {
    def main(args: Array[String]): Unit = {
    //導(dǎo)入MyFile的任意方法
    import MyFile._
    val file:File=new File("c://a.txt")
    //調(diào)用了File的沒有的方法,而readAll是隱式轉(zhuǎn)換的RichFile的方法
    file.readAll()
    }
    }
    object MyFile{
    //將File轉(zhuǎn)換為RichFile
    implicit def m1(file:File):RichFile = new RichFile(file)
    }
    class RichFile(file:File){
    def readAll(): String ={
    Source.fromFile(file).mkString
    }
    }

    方法參數(shù)類型不匹配時

    object Test01 {
    def main(args: Array[String]): Unit = {
    import  ObjectImplicit._
    def m1(worker:Worker) =println("person:"+worker.name)
    m1(new Older("older"))
    m1(new Worker("worker"))
    m1(new Adult("adult"))
    m1(new Young("young"))
    }
    }
    class Older(val name: String)
    class Young(val name: String)
    class Worker(val name: String)
    class Adult(val name: String)
    object ObjectImplicit{
    implicit def objectworker(obj: AnyRef): Worker ={
    if(obj.getClass==classOf[Older]){
      val older=obj.asInstanceOf[Older]
      new Worker(older.name)
    }else if(obj.getClass==classOf[Young]){
      val young=obj.asInstanceOf[Young]
      new Worker(young.name)
    }else if(obj.getClass==classOf[Adult]){
      val adult=obj.asInstanceOf[Adult]
      new Worker(adult.name)
    }else if(obj.getClass==classOf[Worker]){
      val worker=obj.asInstanceOf[Worker]
      worker
    }else{
      new Worker("Null")
    }
    }
    }
向AI問一下細節(jié)
推薦閱讀:
  1. Scala的actor
  2. Scala的泛型

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

AI