Scala 函數(shù)

最常見(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ù)makeIncreasermore為自由變量(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á)式的值

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末赊颠,一起剝皮案震驚了整個(gè)濱河市格二,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌竣蹦,老刑警劉巖顶猜,帶你破解...
    沈念sama閱讀 212,454評(píng)論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異痘括,居然都是意外死亡驶兜,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,553評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門(mén)远寸,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人屠凶,你說(shuō)我怎么就攤上這事驰后。” “怎么了矗愧?”我有些...
    開(kāi)封第一講書(shū)人閱讀 157,921評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵灶芝,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我唉韭,道長(zhǎng)夜涕,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,648評(píng)論 1 284
  • 正文 為了忘掉前任属愤,我火速辦了婚禮女器,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘住诸。我一直安慰自己驾胆,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,770評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布贱呐。 她就那樣靜靜地躺著丧诺,像睡著了一般。 火紅的嫁衣襯著肌膚如雪奄薇。 梳的紋絲不亂的頭發(fā)上驳阎,一...
    開(kāi)封第一講書(shū)人閱讀 49,950評(píng)論 1 291
  • 那天,我揣著相機(jī)與錄音馁蒂,去河邊找鬼呵晚。 笑死,一個(gè)胖子當(dāng)著我的面吹牛远搪,可吹牛的內(nèi)容都是我干的劣纲。 我是一名探鬼主播,決...
    沈念sama閱讀 39,090評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼谁鳍,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼癞季!你這毒婦竟也來(lái)了劫瞳?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 37,817評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤绷柒,失蹤者是張志新(化名)和其女友劉穎志于,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體废睦,經(jīng)...
    沈念sama閱讀 44,275評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡伺绽,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,592評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了嗜湃。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片奈应。...
    茶點(diǎn)故事閱讀 38,724評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖购披,靈堂內(nèi)的尸體忽然破棺而出杖挣,到底是詐尸還是另有隱情,我是刑警寧澤刚陡,帶...
    沈念sama閱讀 34,409評(píng)論 4 333
  • 正文 年R本政府宣布惩妇,位于F島的核電站,受9級(jí)特大地震影響筐乳,放射性物質(zhì)發(fā)生泄漏歌殃。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,052評(píng)論 3 316
  • 文/蒙蒙 一蝙云、第九天 我趴在偏房一處隱蔽的房頂上張望氓皱。 院中可真熱鬧,春花似錦贮懈、人聲如沸匀泊。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,815評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)各聘。三九已至,卻和暖如春抡医,著一層夾襖步出監(jiān)牢的瞬間躲因,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,043評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工忌傻, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留大脉,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,503評(píng)論 2 361
  • 正文 我出身青樓水孩,卻偏偏與公主長(zhǎng)得像镰矿,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子俘种,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,627評(píng)論 2 350