Spark記錄-Scala函數與閉包


函數聲明

Scala函數聲明具有以下形式 -

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

如果不使用等號和方法體,則隱式聲明抽象(abstract)方法。

函數定義

Scala函數定義具有以下形式 -

語法

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

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

語法

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類似的點符號,如下所示:

[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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM