日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Scala学习(十二)高阶函数

發(fā)布時間:2023/12/15 编程问答 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Scala学习(十二)高阶函数 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

2019獨角獸企業(yè)重金招聘Python工程師標準>>>

1.作為值的函數(shù)

在Scala中,你可以在變量中存放函數(shù):

import scala.math._val num = 3.14val fun = ceil _

這段代碼將num設(shè)為3.14, fun設(shè)為ceil函數(shù)。

說明:?ceil函數(shù)后的 _ 意味著你確實指的是這個函數(shù),而不是碰巧忘記給它傳遞參數(shù)。 從技術(shù)上講, _ 將ceil方法轉(zhuǎn)成了函數(shù),在Scala中,你無法直接操縱方法,而只能直接操縱函數(shù)。

怎么使用函數(shù):

  • 調(diào)用它
  • 傳遞它,存放在變量中,或者作為參數(shù)傳遞給另一個函數(shù)

以下是如何調(diào)用存放在fun中的函數(shù):

fun(num) // fun是一個包含函數(shù)的變量,而不是一個固定的函數(shù)

以下是如何將fun傳遞給另一個函數(shù):

Array(3.14, 1.42, 2.0).map(fun) // 將fun傳遞給另一個函數(shù), Array(4.0, 2.0, 2.0)

map方法接收一個函數(shù)參數(shù),將它應(yīng)用到數(shù)組中的所有值,然后返回結(jié)果的數(shù)組。

2.匿名函數(shù)

在Scala中,你不需要給每個函數(shù)命名,它就是匿名函數(shù):

(x: Double) => 3 * x // 將這個函數(shù)存放在變量中 val triple = (x: Double) => 3 * x // 這和用def一樣 def triple(x: Double) = 3 * x// 作為參數(shù)傳遞 Array(3.14, 1.42, 2.0).map((x: Double) => 3 * x) Array(3.14, 1.42, 2.0).map((_ * 3) //或者這樣,最簡形式 Array(3.14, 1.42. 2.0).map{ (x: Double) => 3 * x } // 也可以使用花括號 Array(3.14, 1.42. 2.0) map { (x: Double) => 3 * x } // 使用中置表示法

練習:定義一個函數(shù),入?yún)?個,前兩個數(shù)Int數(shù)字,后兩個是函數(shù),當?shù)谝粋€入?yún)⒋笥?時調(diào)用第一個函數(shù)參數(shù),否則調(diào)用第二個函數(shù)參數(shù)

def call(a:Int, b:Int, f1:(Int,Int)=>Int, f2:(Int,Int)=>Int) = {if(a > 0) f1(a,b) else f2(a,b) }def add(a:Int, b:Int) = a + b def sub(a:Int, b:Int) = a - bval f1 = add _ val f2 = sub _//可以采用如下方式調(diào)用call函數(shù)call(1, 2, f1, f2) call(1, 2, add _, sub _) call(1, 2, add, sub) call(1,2,(a:Int,b:Int)=>a+b,(a:Int,b:Int)=>a-b)

?

3.帶函數(shù)參數(shù)的函數(shù)

def valueAtOneQuarter(f: (Double) => Double) = f(0.25) valueAtOneQuarter(ceil _) // 1.0 valueAtOneQuarter(sqrt _) // 0.5

這里的參數(shù)是一個接受Double并返回Double的函數(shù)。而valueAtOneQuarter的函數(shù)類型是:

((Double) => Double) => Double ; 一個接受函數(shù)參數(shù)的函數(shù),它就稱作高階函數(shù)。例如valueAtOneQuarter。

高階函數(shù)也可以產(chǎn)出另一個函數(shù),即返回一個函數(shù):

def mulBy(factor: Double) = (x: Double) => factor * x mulBy(3) // 返回函數(shù) (x: Double) => 3 * x mulBy函數(shù)的威力在于,它可以產(chǎn)出能夠乘以任何數(shù)額的函數(shù):val quintuple = mulBy(5) quintuple(20) // 100

mulBy函數(shù)的類型為: (Double) => ( (Double) => Double)

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

Scala有比較強大的參數(shù)推導(dǎo):

def valueAtOneQuarter(f: (Double) => Double) = f(0.25) valueAtOneQuarter( (x: Double) => 3 * x ) // 0.75 // 可以簡單寫成 valueAtOneQuarter( (x) => 3 * x ) // 0.75 // 只有一個參數(shù)的情況,還可以省卻參數(shù)的括號: valueAtOneQuarter( x => 3 * x ) // 0.75 // 如果參數(shù)在 => 右側(cè)只出現(xiàn)一次,可以用 _ 替換它 valueAtOneQuarter( 3 * _ ) // 0.75 這些簡寫方式僅在參數(shù)類型已知的情況下有效:val fun = 3 * _ // error val fun = 3 * (_: Double) // OK val fun: (Double) => Double = 3 * _ // OK

5.一些有用的高階函數(shù)

(1 to 9).map(0.1 * _) // _應(yīng)用于所有元素 (1 to 9).map("*" * _).foreach(println _) //打印一個三角形

在這里我們還用到了foreach,它和map很像,只不過他的函數(shù)并不返回任何值

filter方法輸出所有匹配某個特定條件的元素。

(1 to 9).filter(_ % 2 == 0) // 將能被2整除的過濾出來,輸出2,4,6,8

當然,這并不是得到該結(jié)果的最高效方式

// reduceLeft方法接受一個二元的函數(shù),將它應(yīng)用到序列中的所有元素,從左到右 (1 to 9).reduceLeft(_ * _) // 1*2*3*...*8*9

等同于 1*2*3*4*5*6*7*8*9 或者更嚴格地說 ((((((((1*2)*3)*4)*5)*6)*7)*8)*9)// 排序

"Mary has a little lamb".split(" ").sortWith(_.length < _.length)

6.閉包

函數(shù)可以在變量不再處于作用于內(nèi)時被調(diào)用。這樣的函數(shù)稱為閉包, 閉包由代碼和代碼用到的任何非局部變量定義構(gòu)成。 例如:

def mulBy(factor: Double) = (x: Double) => factor * x // 如下調(diào)用 val triple = mulBy(3) val half = mulBy(0.5) println(triple(14) + " " + half(14)) // 42 7

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

mulBy第二次被調(diào)用時,參數(shù)變量被設(shè)為了0.5, 該變量在(x: Double) => factor * x 函數(shù)的函數(shù)體內(nèi)被引用,該函數(shù)被存入half 。

這樣,每一個返回的函數(shù)都要自己的factor設(shè)置。在這里triple和half存儲的函數(shù)訪問了它們作用于范圍外的變量。

7.SAM轉(zhuǎn)換

在Scala中,你可以傳遞函數(shù)作為參數(shù),而在Java中是不可以的(目前),其通常的做法是將動作放在一個實現(xiàn)某接口的類中,然后將該類的一個實例傳遞給另一個方法。在很多時候,這些接口都只有單個抽象方法(single abstract method), 簡稱SAM類型。 例如:

var counter = 0val button = new JButton("Increment") button.addActionListener(new ActionListener {override def actionPerformed(event: ActionEvent) {counter += 1} })

這里使用了樣板代碼,我們希望的是只傳遞一個函數(shù)給addActionListener就好了:

button.addActionListener((event: ActionEvent) => counter += 1)

為了啟用這個語法,你需要提供一個隱士轉(zhuǎn)換,因為addActionListener是Java的方法。

implicit def makeAction(action: ( (ActionEvent) => Unit ) ) = {new ActionListener {override def actionPerformed(event: ActionEvent) { action(event) }} }

只需要簡單的把這個函數(shù)和你的界面代碼放在一起就可以在需要傳入ActionListener 對象的地方傳入任何(ActionEvent) => Unit 類型的函數(shù)了。

?

8.柯里化

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

def mul(x: Int, y: Int) = x * ydef mulOneAtAtime(x: Int) = (y: Int) => x * y?// 定一個接受一個參數(shù),生成另一個接受一個參數(shù)的函數(shù)mulOneAtAtime(6)(7)

這里mulOneAtAtime(6)會返回(y: Int) => 6 * y 類型的函數(shù),然后該函數(shù)又被調(diào)用,最終計算出結(jié)果

Scala支持如下簡寫來定義這樣的柯里化函數(shù):

def mulOneAtAtime (x: Int) (y: Int) = x * y

一個典型應(yīng)用:corresponds方法可以比較兩個序列是否在某個條件下相同:

val a = Array("Hello", "World")val b = Array("hello", "world")a.corresponds (b) (_.equalsIgnoreCase(_))

這里corresponds 是一個柯里化的函數(shù),定義:

def corresponds[B] (that: Seq[B]) (p: (A, B) => Boolean): Boolean

that序列和p函數(shù)是分開的兩個柯里化的參數(shù),類型推斷器先推斷出that是一個String類型的序列,也就是B是String,然后才能在p函數(shù)中推斷出函數(shù)類型是(String, String) => Boolean。

9.控制抽象

對于一個沒有參數(shù)也沒有返回值的函數(shù):

def runInThread(block: () => Unit) {new Thread {override def run() { block() }}.start() }runInThread { () => println("Hi"); Thread.sleep(1000); println("Bye") }

() => 這樣看上比不那么美觀,要向省掉() => 可以使用換名調(diào)用表示方法:在參數(shù)聲明和調(diào)用該函數(shù)參數(shù)的地方略去(),但保留 => :

def runInThread(block: => Unit) {new Thread {override def run() { block }?//注意上面省略了(),這里也要省略}.start() }

在調(diào)用時我們可以省略() =>

runInThread { println("Hi"); Thread.sleep(1000); println("Bye") }

在例如:

def until(condition: => Boolean) (block: => Unit) {if (!condition) {blockuntil(condition) (block)} }var x = 10 until (x == 0) {x -= 1println(x) }

10.return表達式

在Scala中,函數(shù)的返回值就是函數(shù)體的值,即最后一個表達式的值。所有不需要使用return語句返回函數(shù)值。但是,你可以用return來從一個匿名函數(shù)中返回值給包含這個匿名函數(shù)的帶名函數(shù):

def indexOf(str: String, ch: Char): Int = {var i = 0until (i == str.length) {if (str(i) == ch)return ii += 1}return -1 }

如果在帶名函數(shù)中使用return語句,需要給出它的返回類型。

注:如果異常在被送往待命函數(shù)值前,在一個try代碼塊中被捕獲掉了,那么相應(yīng)的值就不會返回。

轉(zhuǎn)載于:https://my.oschina.net/u/3687664/blog/2236840

總結(jié)

以上是生活随笔為你收集整理的Scala学习(十二)高阶函数的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。