最常見(jiàn)的是object內(nèi)部的成員函數(shù)妖异,直接通過(guò)object名稱調(diào)用
此外Scala還有內(nèi)嵌在函數(shù)中的函數(shù)论泛,函數(shù)字面量和函數(shù)值
函數(shù)嵌套 Nested Functions
可以在函數(shù)內(nèi)部嵌套定義別的函數(shù)眼坏,叫做局部函數(shù)local function旷档,只在包含它的代碼塊中可見(jiàn)楞捂,可以訪問(wèn)包含函數(shù)的參數(shù)
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)
}
匿名函數(shù)Anonymous Functions
也叫作叫做函數(shù)字面量function literals梁丘,Scala函數(shù)是頭等函數(shù)first class function,可以用匿名函數(shù)字面量作為值傳遞
函數(shù)字面量被編譯到類中首装,并在運(yùn)行時(shí)實(shí)例化為函數(shù)值function value,常常用作高階函數(shù)的輸入
實(shí)質(zhì)
每個(gè)函數(shù)值都是某個(gè)擴(kuò)展scala
包中FunctionN
特質(zhì) 類的實(shí)例创夜,每個(gè)FunctionN
特質(zhì)都有一個(gè)用于調(diào)用函數(shù)的apply
方法
object Main extends App {
val succ = (x: Int) => x + 1
val anonfun1 = new Function1[Int, Int] {
def apply(x: Int): Int = x + 1
}
assert(succ(0) == anonfun1(0)) // succ匿名類是anonfun1的簡(jiǎn)寫(xiě)
}
scala> val add = (a: Int, b: Int) => a + b
add: (Int, Int) => Int = <function2>
scala> var increase = (x: Int) => x + 1
increase: Int => Int = <function1>
簡(jiǎn)化
當(dāng)賦值給高階函數(shù)的時(shí)候
可以省略參數(shù)類型,通過(guò)類型推斷得到 (x) => x + 1
參數(shù)只有一個(gè)的時(shí)候仙逻,可以去掉輸入?yún)?shù)的括號(hào)x => x + 1
值函數(shù)參數(shù)在右邊只出現(xiàn)一次驰吓,可以使用占位符_ + 1
someNumbers.filter((x: Int) => x > 0)
someNumbers.filter((x) => x > 0) // 目標(biāo)類型化 target typing,可以使用目標(biāo)類型推測(cè)表達(dá)式的類型
someNumbers.filter(x => x > 0) //如果參數(shù)可以推測(cè)系奉,省略圓括號(hào)
占位符
把下劃線當(dāng)做一個(gè)或多個(gè)參數(shù)(只要參數(shù)在函數(shù)字面量?jī)?nèi)只出現(xiàn)一次)的占位符檬贰,進(jìn)一步簡(jiǎn)寫(xiě)函數(shù)字面量
someNumbers.filter(x => x > 0)
//等價(jià)于
someNumbers.filter(_ > 0)
多個(gè)下劃線指代的是多個(gè)參數(shù),不是單個(gè)參數(shù)的重復(fù)使用
val add = (_: Int) + (_: Int) //(a: Int, b: Int) => a + b
var increment=(_:Int)+1
部分應(yīng)用函數(shù) Partially Applied Functions
部分應(yīng)用函數(shù)是一種表達(dá)式缺亮,不需要提供函數(shù)需要的所有參數(shù)翁涤,只需要提供部分,或不提供所需參數(shù)
例如:
//定義函數(shù)
scala> def sum(a: Int, b: Int, c: Int) = a + b + c
sum: (a: Int, b: Int, c: Int)Int
//通過(guò)部分應(yīng)用表達(dá)式 sum _ 自動(dòng)生成類,實(shí)例化為函數(shù)值并賦值
scala> val a = sum _
a: (Int, Int, Int) => Int = <function3>
//調(diào)用函數(shù)值的apply方法
scala> a(1, 2, 3)
res11: Int = 6
提供部分參數(shù)葵礼,Scala編譯器生成一個(gè)新的函數(shù)類号阿,其apply
方法對(duì)應(yīng)缺失的參數(shù)
scala> val b = sum(1, _: Int, 3)
b: Int => Int = <function1>
用下劃線表示整個(gè)參數(shù)列表,可以理解為把def
函數(shù)轉(zhuǎn)換為函數(shù)值鸳粉,因?yàn)椴荒馨殉蓡T函數(shù)或者嵌套函數(shù)直接賦值給變量或者是函數(shù)參數(shù)扔涧,但函數(shù)值是可以直接賦值的
someNumbers.foreach(println _) // someNumbers.foreach(x => println(x))
someNumbers.foreach(println) // 當(dāng)函數(shù)參數(shù)需要一個(gè)函數(shù)時(shí),可以進(jìn)一步省略届谈,例如 def foreach[U](f: A => U): Unit
閉包
閉包是一個(gè)函數(shù)枯夜,內(nèi)部包含對(duì)外部的一個(gè)或多個(gè)變量的引用
函數(shù)makeIncreaser
中more
為自由變量(free variable),x
為綁定變量(bound variable)艰山,帶自由變量的函數(shù)字面量稱為開(kāi)放項(xiàng)(open term)湖雹,內(nèi)部包含指向捕獲變量的引用
var more = 1
def makeIncreaser(more: Int) = (x : Int) => x +more
外部變量在閉包創(chuàng)建后改變,閉包會(huì)受到影響曙搬;閉包對(duì)捕獲變量的改變摔吏,變量在閉包之外同樣受到影響
scala> val inc1 = makeIncreaser(1)
inc1: Int => Int = <function1>
scala> val inc9999 = makeIncreaser(9999)
inc9999: Int => Int = <function1>
scala> inc1(10)
res20: Int = 11
scala> inc9999(10)
res21: Int = 10009
特殊函數(shù)調(diào)用的形式
Scala支持重復(fù)參數(shù),命名實(shí)參织鲸,默認(rèn)參數(shù)
重復(fù)參數(shù) Repeated parameters
函數(shù)的最后一個(gè)參數(shù)可以是重復(fù)的舔腾,在參數(shù)的類型之后放一個(gè)星號(hào)來(lái)指明重復(fù)的參數(shù),參數(shù)數(shù)目可以從0到任意多
printStrings("Hello", "Scala", "Python")
def printStrings( args:String* ) = {}
函數(shù)內(nèi)部重復(fù)參數(shù)的類型是對(duì)應(yīng)類型的數(shù)組搂擦,但是不能直接傳遞數(shù)組稳诚,而是在數(shù)組名稱后加上: _*
,指示編譯器把數(shù)組的每個(gè)元素作為參數(shù)傳遞
printString(args: _*)
命名實(shí)參 Named Arguments
正常情況下瀑踢,參數(shù)按被調(diào)用函數(shù)的參數(shù)順序依次匹配
命名參數(shù)允許以不同的順序?qū)?shù)傳遞給函數(shù)扳还,每個(gè)實(shí)參前面加上形參名稱和等號(hào)
object Demo {
def main(args: Array[String]) {
printInt(b = 5, a = 7);
}
def printInt( a:Int, b:Int ) = {
println("Value of a : " + a ); //7
println("Value of b : " + b );//5
}
}
默認(rèn)參數(shù) Default Parameter
Scala 可以為函數(shù)參數(shù)指定默認(rèn)參數(shù)值,Java語(yǔ)言不支持該功能橱夭,必須通過(guò)重載才能間接實(shí)現(xiàn)
有默認(rèn)值的實(shí)參可以選擇忽略氨距,設(shè)為的默認(rèn)值,可以和命名實(shí)參結(jié)合使用
def addInt( a:Int = 5, b:Int = 7 ) : Int = {
var sum:Int = 0
sum = a + b
return sum
}
addInt() //12
addInt(a = 3) //10
addInt(b = 15) //20
高階函數(shù) Higher-Order Functions
使用其他函數(shù)作為參數(shù)棘劣,或其返回值是一個(gè)函數(shù)
object Files {
object FileMatcher {
private def filesHere = (new java.io.File(".")).listFiles
private def filesMatching(matcher: String => Boolean) =
for (file <- filesHere; if matcher(file.getName))
yield file
def filesEnding(query: String) =
filesMatching(_.endsWith(query))
def filesContaining(query: String) =
filesMatching(_.contains(query))
def filesRegex(query: String) =
filesMatching(_.matches(query))
}
}
柯里化 Currying
函數(shù)定義多個(gè)參數(shù)列表俏让,使用部分參數(shù)列表調(diào)用某個(gè)方法時(shí),產(chǎn)生一個(gè)將缺少的參數(shù)列表作為其參數(shù)的函數(shù)
scala> def plainOldSum(x: Int, y: Int) = x + y
plainOldSum: (x: Int, y: Int)Int
scala> def curriedSum(x: Int)(y: Int) = x + y
curriedSum: (x: Int)(y: Int)
scala> curriedSum(1)(2) //實(shí)質(zhì)上是接連進(jìn)行了兩次函數(shù)調(diào)用茬暇,中間的函數(shù)值是 curriedSum(1)_
res5: Int = 3
傳名參數(shù) by-name parameters
在函數(shù)內(nèi)部進(jìn)行參數(shù)表達(dá)式的值計(jì)算首昔,傳名類型中空的參數(shù)列表被省略,只用寫(xiě) =>
糙俗,僅用于形參
var assertionsEnabled = true
def myAssert(predicate: () => Boolean) =
if (assertionsEnabled && !predicate())
throw new AssertionError
//正確調(diào)用
myAssert(() => 5 > 3)
// 錯(cuò)誤調(diào)用
myAssert(5 > 3) // 缺少() =>
//傳名調(diào)用
def byNameAssert(predicate: => Boolean) =
if (assertionsEnabled && !predicate)
throw new AssertionError
//正確調(diào)用
byNameAssert(5 > 3)
byNameAssert(5 > 3)
括號(hào)中的表達(dá)式不是直接計(jì)算的勒奇,而是創(chuàng)建一個(gè)函數(shù)值,在它的apply
方法進(jìn)行比較
在一個(gè)函數(shù)內(nèi)部多次使用傳名調(diào)用值時(shí)巧骚,每次都會(huì)重新計(jì)算一次表達(dá)式的值