溫馨提示×

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

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

Scala筆記整理(五):函數(shù)式編程

發(fā)布時(shí)間:2020-10-24 19:45:17 來源:網(wǎng)絡(luò) 閱讀:2280 作者:xpleaf 欄目:大數(shù)據(jù)

[TOC]


作為值傳遞的函數(shù)

測試代碼如下:

package cn.xpleaf.bigdata.p4.function

/**
  * scala中關(guān)于函數(shù)的操作
  */
object _01FunctionOps {
  def main(args: Array[String]): Unit = {
    functionOps1
  }

  /**
    * 作為值傳遞的函數(shù)
    * 將一個(gè)函數(shù)作為值傳遞給另外一個(gè)函數(shù)變量的時(shí)候,約定需要在函數(shù)后面加上:空格和下劃線
    * 相當(dāng)于數(shù)據(jù)庫中的別名,或者數(shù)據(jù)庫表對(duì)應(yīng)的視圖
    */
  def functionOps1: Unit = {
    def sayHi(name:String) = println("Hello, " + name)

    def sayHello = sayHi _

    sayHello("xpleaf")
  }
}

輸出結(jié)果如下:

Hello, xpleaf

匿名函數(shù)

測試代碼如下:

package cn.xpleaf.bigdata.p4.function

/**
  * scala中關(guān)于函數(shù)的操作
  */
object _01FunctionOps {
  def main(args: Array[String]): Unit = {
    functionOps2
  }

  /**
    * 匿名函數(shù),說白了就是沒有函數(shù)名字
    *     匿名函數(shù)就和java中的匿名內(nèi)部類一樣,是只適合使用一次的函數(shù)
    *     一般如果一個(gè)函數(shù)的參數(shù)是一個(gè)函數(shù),這種情況下多用匿名函數(shù)來作為參數(shù)進(jìn)行傳遞
    */
  def functionOps2: Unit = {
    val printName = (name:String) => println("你好," + name)
    printName("xpleaf")
  }

}

輸出結(jié)果如下:

你好,xpleaf

其實(shí)前面在學(xué)習(xí)ArrayBuffer的時(shí)候已經(jīng)有使用過匿名函數(shù):

scala> val ab = ArrayBuffer[Int](3, 8, 2, 20, 5, 7)
ab: scala.collection.mutable.ArrayBuffer[Int] = ArrayBuffer(3, 8, 2, 20, 5, 7)
scala> ab.sortWith((v1, v2) => v1 > v2)
res209: scala.collection.mutable.ArrayBuffer[Int] = ArrayBuffer(20, 8, 7, 5, 3, 2)

帶函數(shù)參數(shù)的函數(shù)(高階函數(shù))

說明的作用有兩個(gè)(匿名函數(shù)作為參數(shù)和返回值為匿名函數(shù)),具體參考下面的測試代碼:

package cn.xpleaf.bigdata.p4.function

/**
  * scala中關(guān)于函數(shù)的操作
  */
object _01FunctionOps {
  def main(args: Array[String]): Unit = {
//    functionOps1
//    functionOps2
    functionOps3
  }

  /**
    * scala的高階函數(shù),就是函數(shù)的 [參數(shù)是函數(shù)] 的函數(shù),把這種函數(shù)稱為高階函數(shù)
    */
  def functionOps3: Unit = {

    // 1.匿名函數(shù)作為參數(shù)
    def highOrderFunc(name:String, func:(String) => Unit): Unit = {
      func(name)
    }

    highOrderFunc("xpleaf", (name:String) => println("Hello, " + name))

    // 2.將匿名函數(shù)作為返回值傳遞給另外一個(gè)函數(shù)
    def getGoodBayFunction(gMsg: String) = (gName: String) => println(gMsg + ", " + gName)

    val goodbayFunction = getGoodBayFunction("good bye")
    goodbayFunction("xpleaf")

  }
}

輸出結(jié)果如下:

Hello, xpleaf
good bye, xpleaf

參數(shù)(類型)推斷

測試代碼如下:

package cn.xpleaf.bigdata.p4.function

import scala.collection.mutable.ArrayBuffer

/**
  * scala中關(guān)于函數(shù)的操作
  */
object _01FunctionOps {
  def main(args: Array[String]): Unit = {
//    functionOps1
//    functionOps2
//    functionOps3
    functionOps4
  }

  /**
    * 對(duì)于匿名函數(shù)的省略寫法
    */
  def functionOps4: Unit = {
    val ab = ArrayBuffer[Int](1, 2, 3, 4, 5)

    // val newAB = ab.map((x:Int) => x * 100)
    // val newAB = ab.map((x) => x * 100)
    // val newAB = ab.map(x => x * 100)
    val newAB = ab.map(100 * _)
    println(newAB)  // ArrayBuffer(100, 200, 300, 400, 500)

  }
}

輸出結(jié)果如下:

ArrayBuffer(100, 200, 300, 400, 500)

常見高階函數(shù)——map函數(shù)

遍歷集合中的每一個(gè)元素,返回也是一個(gè)集合,集合大小和之前集合相等。
  • 快速產(chǎn)生0.1, 0.2, 0.3等方式的數(shù)字
scala> (1 to 9).map(0.1 * _).foreach(println(_))
0.1
0.2
0.30000000000000004
0.4
0.5
0.6000000000000001
0.7000000000000001
0.8
0.9
  • 打印三角形
scala> (1 to 9).map("*" * _).foreach(println(_))
*
**
***
****
*****
******
*******
********
*********

在這里,我們還用到了foreach,它和map很像,只不過它的函數(shù)并不返回任何值,foreach只是簡單的將函數(shù)應(yīng)用到每個(gè)元素而已。

常見高階函數(shù)——filter函數(shù)

按照過濾條件,將原集合中不符合條件的數(shù)據(jù)過濾掉
  • 輸出所有匹配某個(gè)特定條件的元素,得到一個(gè)序列中的所有偶數(shù)
scala> (1 to 9).filter(line => line % 2 == 0).foreach(println(_))
2
4
6
8

scala> (1 to 9).filter(_ % 2 ==0).foreach(println)
2
4
6
8

常見高階函數(shù)——reduce函數(shù)

scala> (1 to 9).reduce((v1:Int, v2:Int) => v1 + v2)
res4: Int = 45
scala> (1 to 9).reduce(_ + _)
res6: Int = 45
scala> (1 to 9).reduceLeft(_ + _)
res7: Int = 45
scala> (1 to 9).reduceRight(_ + _)
res8: Int = 45

可以寫下面一個(gè)函數(shù)來驗(yàn)證reduce函數(shù)的執(zhí)行過程:

scala> val process = (v1:Int, v2:Int) => println(s"v1=${v1}, v2=${v2}")
process: (Int, Int) => Unit = <function2>
scala> def pro(v1:Int, v2:Int):Int = {
     |   println(s"v1=${v1}, v2=${v2}")
     |   v1 + v2
     | }
pro: (v1: Int, v2: Int)Int
  • reduce的執(zhí)行流程
scala> (1 to 9).reduce((v1:Int, v2:Int) => pro(v1, v2))
v1=1, v2=2
v1=3, v2=3
v1=6, v2=4
v1=10, v2=5
v1=15, v2=6
v1=21, v2=7
v1=28, v2=8
v1=36, v2=9
res0: Int = 45
  • reductLeft的執(zhí)行流程
scala> (1 to 9).reduceLeft((v1:Int, v2:Int) => pro(v1, v2))
v1=1, v2=2
v1=3, v2=3
v1=6, v2=4
v1=10, v2=5
v1=15, v2=6
v1=21, v2=7
v1=28, v2=8
v1=36, v2=9
res2: Int = 45
  • reductRight的執(zhí)行流程
scala> (1 to 9).reduceRight((v1:Int, v2:Int) => pro(v1, v2))
v1=8, v2=9
v1=7, v2=17
v1=6, v2=24
v1=5, v2=30
v1=4, v2=35
v1=3, v2=39
v1=2, v2=42
v1=1, v2=44
res3: Int = 45

這樣的話執(zhí)行過程就非常清晰了,reduce和reduceLeft都是從左邊的操作數(shù)開始,而reduceRight是從右邊的操作數(shù)開始。

常見高階函數(shù)——sortWith函數(shù)

scala> (1 to 9).sortWith((v1:Int, v2:Int) => v1 > v2).foreach(println(_))
9
8
7
6
5
4
3
2
1

scala> (1 to 9).sortWith(_ > _).foreach(println)
9
8
7
6
5
4
3
2
1

閉包

函數(shù)的變量不在其作用域內(nèi)被調(diào)用,就是閉包的概念,看下面一個(gè)例子:

def closePackage: Unit ={
    def mulBy(factor:Double) = (x:Double) => factor * x
    val triple = mulBy(3)
    val half = mulBy(0.5)
    println(triple(14) +" " + half(14)) //42, 7
}

1)mulBy的首次調(diào)用將參數(shù)變量factor設(shè)為3,。該變量在(x:Double)=&gt;factor *x函數(shù)的函數(shù)體內(nèi)被引用。該函數(shù)被存入triple.然后參數(shù)變量factor從運(yùn)行時(shí)的棧上被彈出。

2)mulBy再次被調(diào)用,這次factor被設(shè)為0.5.該變量在(x:Double)=&gt;factor *x函數(shù)的函數(shù)體內(nèi)被引用,該函數(shù)被存入half.

每一個(gè)函數(shù)被稱為閉包(closure)。閉包有代碼和代碼用到的任何非局部變量定義構(gòu)成。

其實(shí)上面的mulBy函數(shù)就類似于下面這個(gè):

def mulBy1(factor:Double, x:Double) = {
    factor * x
}

原本還希望進(jìn)一步寫成下面這樣子的:

def mulBy2(factor:Double, x:Double) = {
    def work(x:Double) = {
        factor * x
    }
    return work
}

但在scala中不支持這樣的寫法,下面這樣寫才可以:

def mulBy2(factor:Double) = {
    (x:Double) => factor * x
}
// 加個(gè)return也不行

之前在Python中使用過閉包,類似上面的例子,Python就可以這樣寫:

def mulBy(factor):
    def work(x):
        return factor * x
    return work

測試如下:

>>> def mulBy(factor):
...     def work(x):
...             return factor * x
...     return work
...
>>> triple = mulBy(3)
>>> half = mulBy(0.5)
>>> triple(14)
42
>>> half(14)
7.0

當(dāng)然,只是Python的語法格式就沒有scala那么靈活了。

柯里化(currying函數(shù))

1、柯里化(currying)指的是將原來接受2個(gè)參數(shù)的函數(shù)變成新的接受一個(gè)參數(shù)的函數(shù)的過程。新的函數(shù)返回一個(gè)以原有第二個(gè)參數(shù)作為參數(shù)的函數(shù)。

2、在函數(shù)調(diào)用的過程中,就變?yōu)榱藘蓚€(gè)函數(shù)連續(xù)調(diào)用的形式。在Spark源碼中,也有體現(xiàn),所以對(duì)()()這種形式的Curring函數(shù),一定要掌握。

以下函數(shù)接受一個(gè)參數(shù),生成另一個(gè)接受單個(gè)參數(shù)的函數(shù),要計(jì)算兩個(gè)數(shù)的乘積,調(diào)用如下:

/**
    * curryingFunction: 柯里化函數(shù)
    */
def curryingFunction ={
    def totalSum(x:Int, y:Int) = println( x + y)

    //totalSum(4,5)

    def totalSumAtTime(x:Int) = (y:Int) => x + y
    println(totalSumAtTime(4)(5))
}
向AI問一下細(xì)節(jié)

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

AI