Spark記錄-Scala函數與閉包

函數聲明

Scala函數聲明具備如下形式 -java

def functionName ([list of parameters]) : [return type] 
Scala

若是不使用等號和方法體,則隱式聲明抽象(abstract)方法。程序員

函數定義

Scala函數定義具備如下形式 -shell

語法編程

def functionName ([list of parameters]) : [return type] = { function body return [expr] } 
Scala

這裏,返回類型能夠是任何有效的Scala數據類型,參數列表將是由逗號分隔的變量列表,參數列表和返回類型是可選的。與Java很是類似,返回語句能夠與表達式一塊兒使用,以防函數返回值。 如下是將兩個整數相加並返回其總和的函數,閉包

語法app

object add { def addInt( a:Int, b:Int ) : Int = { var sum:Int = 0 sum = a + b return sum } } 
Scala

一個不返回任何東西的函數能夠返回一個相似在Java中的void類型,並表示該函數不返回任何內容。 在Scala中不返回任何東西的函數稱爲過程。編程語言

語法函數式編程

object Hello{ def printMe( ) : Unit = { println("Hello, Scala!") } } 
Scala

調用函數

Scala爲調用方法提供了許多句法變體。如下是調用方法的標準方法 -函數

functionName( list of parameters ) 
Scala

若是使用對象的實例調用函數,那麼可以使用與Java相似的點符號,以下所示:ui

[instance.]functionName( list of parameters ) 
Scala

嘗試如下示例程序來定義並調用相同的函數 -

示例 -

object Demo { def main(args: Array[String]) { println( "Returned Value : " + addInt(5,7) ); } def addInt( a:Int, b:Int ) : Int = { var sum:Int = 0 sum = a + b return sum } } 
Scala

將上述程序保存在源文件:Demo.scala中,使用如下命令編譯和執行此程序。

Scala函數是Scala編程的核心,所以Scala被認爲是函數式編程語言。如下是與Scala函數相關的幾個重要概念,Scala程序員應該要理解。

Scala按名稱調用函數



object Demo { def main(args: Array[String]) { delayed(time()); } def time() = { println("Getting time in nano seconds") System.nanoTime } def delayed( t: => Long ) = { println("In delayed method") println("Param: " + t) } }

Scala命名參數的函數

在正常的函數調用中,調用的參數按照被調用函數定義的參數順序逐個匹配。命名參數容許您以不一樣的順序將參數傳遞給函數。語法只是每一個參數前面都有一個參數名稱和一個等號。

嘗試如下程序,它是一個簡單的例子來顯示具備命名參數的函數。

object Demo { def main(args: Array[String]) { printInt(b = 5, a = 7); } def printInt( a:Int, b:Int ) = { println("Value of a : " + a ); println("Value of b : " + b ); } } 
Scala

將上述程序保存在源文件:Demo.scala中,使用如下命令編譯和執行此程序。

Scala可變參數的函數

Scala容許指定函數的最後一個參數可重複。 這容許客戶端將可變長度參數列表傳遞給函數。 這裏,打印字符串函數裏面的args類型,被聲明爲類型String *,其實是Array [String]

嘗試如下程序,這是一個簡單的例子來演示如何使用帶有可變參數的函數。



object Demo { def main(args: Array[String]) { printStrings("Hello", "Scala", "Python"); } def printStrings( args:String* ) = { var i : Int = 0; for( arg <- args ){ println("Arg value[" + i + "] = " + arg ); i = i + 1; } } }

Scala遞歸函數

遞歸在純功能編程中起着重要做用,Scala支持遞歸函數。 遞歸表示一個函數能夠重複調用自身。

嘗試如下程序,它是一個很好的遞歸示例,它計算給定參數(數字)的階乘。

示例



object Demo { def main(args: Array[String]) { for (i <- 1 to 10) println( "Factorial of " + i + ": = " + factorial(i) ) } def factorial(n: BigInt): BigInt = { if (n <= 1) 1 else n * factorial(n - 1) } }

Scala遞歸函數

Scala容許您指定函數參數的默認值。 這樣一個參數能夠從函數調用中選擇性地省略,在這種狀況下,相應的參數值將使用默認值。若是指定其中一個參數,則使用該參數將傳遞第一個參數,第二個參數將從默認值中獲取。

嘗試如下示例,它是爲函數指定默認參數的示例 -

示例



object Demo { def main(args: Array[String]) { println( "Returned Value : " + addInt() ); } def addInt( a:Int = 5, b:Int = 7 ) : Int = { var sum:Int = 0 sum = a + b return sum } }

Scala高階函數

Scala容許定義高階函數。它是將其餘函數做爲參數或其結果是函數的函數。

嘗試如下示例程序,apply()函數接受另外一個函數f和值v,並將函數f應用於v

示例



object Demo { def main(args: Array[String]) { println( apply( layout, 10) ) } def apply(f: Int => String, v: Int) = f(v) def layout[A](x: A) = "[" + x.toString() + "]" }

Scala嵌套函數

Scala容許您定義函數內部的函數,而在其餘函數中定義的函數稱爲局部函數。這是一個階乘計算器的實現,咱們使用傳統的技術來調用第二個嵌套方法來完成工做。

嘗試如下程序來了解如何實現嵌套函數。

示例



object Demo { def main(args: Array[String]) { println( factorial(0) ) println( factorial(1) ) println( factorial(2) ) println( factorial(3) ) } def factorial(i: Int): Int = { def fact(i: Int, accumulator: Int): Int = { if (i <= 1) accumulator else fact(i - 1, i * accumulator) } fact(i, 1) } }

Scala匿名函數

Scala提供了一個相對輕量級的語法來定義匿名函數。源代碼中的匿名函數稱爲函數文字,在運行時,函數文字被實例化爲稱爲函數值的對象。

Scala支持一級函數,函數能夠用函數文字語法表達,即(x:Int)=> x + 1,該函數能夠由一個叫做函數值的對象來表示。

嘗試如下表達式,它爲整數建立一個後繼函數 -

var inc = (x:Int) => x+1 
Scala

變量inc如今是一種能夠像函數那樣使用的函數 -

var x = inc(7)-1 
Scala

還能夠以下定義具備多個參數的函數:

var mul = (x: Int, y: Int) => x*y 
Scala

變量mul如今是能夠像函數那樣使用的函數 -

println(mul(3, 4)) 
Scala

也能夠定義不帶參數的函數,以下所示:

var userDir = () => { System.getProperty("user.dir") } 
Scala

變量userDir如今是能夠像函數那樣使用的函數 -

println( userDir )

Scala部分應用函數

當在調用一個函數時,把這個函數應用到參數中。 若是您傳遞全部預期的參數,則表示您已徹底應用它。 若是隻傳遞幾個參數並非所有參數,那麼將返回部分應用的函數。這樣就能夠方便地綁定一些參數,其他的參數可稍後填寫補上。

嘗試如下,下面是一個簡單的示例程序用來演示如何使用部分應用函數 -

import java.util.Date object Demo { def main(args: Array[String]) { val date = new Date log(date, "message1" ) Thread.sleep(1000) log(date, "message2" ) Thread.sleep(1000) log(date, "message3" ) } def log(date: Date, message: String) = { println(date + "----" + message) } } 
Scala

將上述程序保存在源文件:Demo.scala 中,使用如下命令編譯和執行此程序。

D:/> scalac Demo.scala D:/> scala Demo Mon Dec 02 12:52:41 CST 2018----message1 Mon Dec 02 12:52:41 CST 2018----message2 Mon Dec 02 12:52:41 CST 2018----message3 
Scala

這裏,log()方法有兩個參數:datemessage。 咱們想要屢次調用該方法,具備相同的日期值,但不一樣的消息值。能夠經過將參數部分地應用到log()方法來消除將日期傳遞給每一個調用的干擾。爲此,首先將值綁定到date參數,並將第二個參數綁定到其位置。 結果是存儲在變量中的部分應用函數。

嘗試如下示例程序以僅使用未綁定的參數消息來調用此新方法。

import java.util.Date object Demo { def main(args: Array[String]) { val date = new Date val logWithDateBound = log(date, _ : String) logWithDateBound("message1" ) Thread.sleep(1000) logWithDateBound("message2" ) Thread.sleep(1000) logWithDateBound("message3" ) } def log(date: Date, message: String) = { println(date + "----" + message) } } 
Scala

將上述程序保存在源文件:Demo.scala中,使用如下命令來編譯和執行此程序。

D:\>scalac Demo.scala
D:\>scala Demo

Mon Dec 02 12:53:56 CST 2018----message1
Mon Dec 02 12:53:56 CST 2018----message2
Mon Dec 02 12:53:56 CST 2018----message3

Scala柯里化函數

柯里化(Currying)函數是一個帶有多個參數,並引入到一個函數鏈中的函數,每一個函數都使用一個參數。 柯里化(Currying)函數用多個參數表定義,以下所示:

def strcat(s1: String)(s2: String) = s1 + s2 
Scala

或者,還可使用如下語法定義柯里化(Currying)函數 -

def strcat(s1: String) = (s2: String) => s1 + s2 
Scala

如下是調用柯里化(Currying)函數的語法 -

strcat("foo")("bar") 
Scala

您能夠根據須要在柯里化(Currying)函數上定義兩個以上的參數。嘗試下面一個簡單的示例程序用來了解如何使用柯里化(Currying)函數 -

object Demo { def main(args: Array[String]) { val str1:String = "Hello, " val str2:String = "Scala!" println( "str1 + str2 = " + strcat(str1)(str2) ) } def strcat(s1: String)(s2: String) = { s1 + s2 } } 
Scala

將上述程序保存在源文件:Demo.scala 中,使用如下命令編譯和執行此程序。

D:\> scalac Demo.scala D:\> scala Demo str1 + str2 = Hello, Scala!

Scala閉包

閉包是一個函數,它返回值取決於在此函數以外聲明的一個或多個變量的值。

如下代碼是一個匿名函數。

val multiplier = (i:Int) => i * 10 
Scala

這裏,函數體i * 10中使用的惟一變量是i,它被定義爲該函數的一個參數。嘗試如下代碼 -

val multiplier = (i:Int) => i * factor 
Scala

乘數有兩個自由變量:ifactori是函數的一個正式參數。 所以,每當調用乘數時,它必然會有一個新的值。然而,factor不是一個正式的參數,那這是什麼呢? 再增長一行代碼。

var factor = 3 val multiplier = (i:Int) => i * factor 
Scala

如今factor參考了函數以外的變量,可是在閉合的範圍內。函數引用factor,每次讀取其當前值。 若是函數沒有外部引用,那麼它自己就會被簡單地關閉,不須要外部上下文。

請嘗試如下示例程序 -

object Demo { def main(args: Array[String]) { println( "multiplier(1) value = " + multiplier(1) ) println( "multiplier(2) value = " + multiplier(2) ) } var factor = 3 val multiplier = (i:Int) => i * factor } 
Scala

將上述程序保存在源代碼:Demo.scala中,使用如下命令編譯和執行此程序。

D:\>scalac Demo.scala
D:\>scala Demo

multiplier(1) value = 3
multiplier(2) value = 6
相關文章
相關標籤/搜索