在使用函數(shù)之前必須先定義函數(shù)。定義函數(shù)的語法格式如下:
fun 函數(shù)名(形參列表)[ : 返回值類型] {
}
使用":Unit"指定返回Unit代表沒有返回值。相當于java的void(:Unit 可以忽略,默認的是Unit的類型)

函數(shù)的形參的定義:

當然可以定義返回某個類型的函數(shù):

Kotlin函數(shù)也支持單表達式函數(shù):對于單表達式函數(shù)而言,編譯器可以推斷出函數(shù)的返回值類型,一次kotlin允許省略點返回值的類型。

Kotlin支持函數(shù)的形參有默認值:如果第二個參數(shù)不傳,就默認傳的是2。如果第二個參數(shù)重新傳值就相當于將傳來的3把2替換掉。(切記:帶有默認值的形參一定要放在不帶有默認值的形參的后邊)。同樣你也可以帶參數(shù)名來調(diào)用,這樣在調(diào)用的時候就可以打亂順序。


Kotlin允許定義個數(shù)可變的參數(shù),從而允許為函數(shù)指定數(shù)量不確定的形參。在形參的類型前添加vararg修飾,怎表明該形參可以接受多個參數(shù)值。

Kotlin支持在函數(shù)體內(nèi)定義函數(shù),這種被放在函數(shù)體內(nèi)定義函數(shù)稱為局部函數(shù)。

Kotlin的高階函數(shù)
首先Kotlin不是純粹的面向對象語言,Kotlin的函數(shù)也是一等公民,因此函數(shù)本身也具有自己的類型。(看到這里只熟悉java的朋友會有點蒙圈,怎么函數(shù)自己也有自己的類型。那么請聽我細細的講解一下)

首先定義一個2個參數(shù),每個參數(shù)都是Int類型和返回值是String類型的變量,之后創(chuàng)建一個pow函數(shù)也是同類型,并將pow函數(shù)賦值給了myFun。(當直接訪問一個函數(shù)的函數(shù)引用, 而不是調(diào)用函數(shù)時,需要函數(shù)名錢添加兩個冒號,而且不能再函數(shù)后面添加圓括號-----一旦添加圓括號就變成了調(diào)用函數(shù),而不是訪問函數(shù)的引用)
Kotlin可以使用函數(shù)類型作為形參類型:

Kotlin:使用函數(shù)類型作為返回值類型:

Kotlin局部函數(shù)與Lambda表達式:
回顧上,用lambda表達式代替局部函數(shù):
定義Lambda表達式總是被大括號括著, 形參列表在->之前聲明,參數(shù)類型可以省略,函數(shù)體放在->之后,函數(shù)的最后一個表達式自定被作為Lambda表達式的返回值,無需使用return關鍵字。

將Lambda單做一個表達式出來


調(diào)用Lambda表達式的約定
Kotlin語言有一個約定,如果函數(shù)的最后一個參數(shù)是函數(shù)類型,而且你打算傳入一個Lambda表達式作為相應的參數(shù),那么就允許在圓括號之外指定Lambda表達式,(這種用法也不是kotlin獨有的,在其他語言中這種用法被稱為“尾隨閉包”)根據(jù)介紹建議將函數(shù)類型的形參放在形參列表的最后,這樣方便以后傳入Lambda表達式作為參數(shù)。?

Lambda表達式雖然簡潔,方便,但是它有一個嚴重的缺陷就是它表達式不能指定返回值類型。因此如果kotlin無法推斷Lambda表達式的返回值類型。此時就需要顯示指定的返回值類型,匿名函數(shù)可以代替Lambda表達式。如下:

與不普通函數(shù)不同的是,如果系統(tǒng)可以推斷出函數(shù)的形參類型,那么匿名函數(shù)允許省略形參類型

匿名函數(shù)和Lambda表達式的return
匿名函數(shù)的本質依然是函數(shù),因此匿名函數(shù)的return則返回函數(shù)的本身,而Lambda表達式的return返回的是所在的函數(shù)。例如:

內(nèi)聯(lián)函數(shù)
簡單介紹一下內(nèi)聯(lián)函數(shù)的產(chǎn)生條件(當為函數(shù)傳入函數(shù)或者lambda表達式作為參數(shù)的調(diào)用過程中,程序要將執(zhí)行順序轉移到被調(diào)用表達式或者函數(shù)所在的內(nèi)存地址當被調(diào)用表達式或者函數(shù)執(zhí)行完后,再返回原來函數(shù)執(zhí)行的地方)在上邊的轉移過程中,系統(tǒng)處理如下的事情:
1.為被調(diào)用的表達式或者函數(shù)創(chuàng)建一個對象。
2.為被調(diào)用的表達式或者函數(shù)所捕獲變量創(chuàng)建一個副本。
3.在跳轉被調(diào)用的表達式或者函數(shù)所在的地址之前,要先保護現(xiàn)場并記錄執(zhí)行地址;從被調(diào)用的表達式或者函數(shù)地址返回時,要先回復現(xiàn)場,并按原來保存的地址繼續(xù)執(zhí)行。也就是通常所說的壓棧和出棧。 從上邊介紹不難看出,函數(shù)調(diào)用會產(chǎn)生一定的時間和空間的花銷。如果別調(diào)用的表達式或者函數(shù)的代碼量的本身不大,而且該表達式或者函數(shù)經(jīng)常被調(diào)用,那么這個時間和空間開銷的損耗就不是很劃算了。為了避免產(chǎn)生函數(shù)的調(diào)用過程,我們可以考慮直接把被調(diào)用的表達式或者函數(shù)的代碼嵌入原來的執(zhí)行流中,簡單的說就是將代碼復制粘貼過去。為了讓編譯器幫我們干這個復制和粘貼的活,可以通過內(nèi)聯(lián)函數(shù)來實現(xiàn)。
使用內(nèi)聯(lián)函數(shù)非常的簡單,只要使用inline關鍵字修飾帶函數(shù)的形參的函數(shù)即可。例如:

內(nèi)聯(lián)函數(shù)并不是在什么情況下都可以提高性能的,我們了解到內(nèi)聯(lián)函數(shù)是根據(jù)目標代碼的增加為代價來節(jié)省時間開銷的,因此是否可以使用內(nèi)聯(lián)函數(shù)的答案是;如果被調(diào)用的Lambda表達式或者函數(shù)包含大量的執(zhí)行代碼,那么就不應該使用內(nèi)聯(lián)函數(shù);如果被調(diào)用的Lambda表達式或者函數(shù)只包含簡單的執(zhí)行代碼(尤其是單表達式),那么就應該使用內(nèi)聯(lián)函數(shù)。
使用inline修飾函數(shù)之后,所有傳入該函數(shù)的Lambda表達式或函數(shù)都會被內(nèi)聯(lián)化;如果我們又希望該函數(shù)中一個或者幾個函數(shù)類型的形參不會被內(nèi)聯(lián)化,怎可以考慮使用noinline修飾它們。

前面已經(jīng)提過了,在Lambda表達式中直接使用return不是用于返回該表達式,而是用于返回該表達式所在的函數(shù)(當然可以用return@ + name指定返回到哪里)但是記住:在默認情況下,在Lambda表達式中并不允許直接使用return,這是因為非內(nèi)聯(lián)的Lambda表達式,該Lambda表達式會額外生成一個函數(shù)對象,因此這種表達式中的return不可能用于返回它所在的函數(shù)。由于內(nèi)聯(lián)的Lambda表達式會被直接復制,粘貼到調(diào)用他的函數(shù)中,故可以在該Lambda表達式中可以使用return。
最后補充一下,目前內(nèi)聯(lián)Lambda表達式暫不支持break和continue流程控制,但是未來kotlin計劃支持該功能。