上一篇:Kotlin一步一步學(xué)(四) -- 擴(kuò)展函數(shù)和運(yùn)算符
定義
如果一個(gè)函數(shù)接收另一個(gè)函數(shù)作為參數(shù),或者返回值的類型是另外一個(gè)函數(shù),那么該函數(shù)就稱為高階函數(shù)
不同于定義一個(gè)普通的字段類型绳姨,函數(shù)類型參數(shù)的語法是有點(diǎn)特殊的,基本規(guī)則如下:
(String, Int)-> Unit
將上述的函數(shù)類型添加到某個(gè)函數(shù)的參數(shù)聲明或者返回值聲明上钠糊,那么這個(gè)函數(shù)就是一個(gè)高階函數(shù)了。具體如下所示:
fun example(func : (String , Int) -> Unit){
func("hello world",123)
}
這里的example()函數(shù)接收了一個(gè)函數(shù)類型的參數(shù),因此example()函數(shù)就是一個(gè)高階函數(shù)。而調(diào)用一個(gè)函數(shù)類型的參數(shù)仑撞,它的語法類似于調(diào)用一個(gè)普通的函數(shù),只需要在參數(shù)名的后面加上一對(duì)括號(hào)妖滔,并在括號(hào)中傳入必要的參數(shù)就可以了。很簡(jiǎn)單吧桶良。座舍。。
用途
高階函數(shù)允許讓函數(shù)類型的參數(shù)來決定函數(shù)的執(zhí)行邏輯陨帆。也就是說即使是同一個(gè)高階函數(shù)曲秉,只要傳入不同的函數(shù)類型參數(shù),那么它的執(zhí)行邏輯和最終的返回結(jié)果就可能是完全不同的疲牵。
案例:定義一個(gè)叫作num1AndNum2()的高階函數(shù)承二,并讓它接收兩個(gè)整型和一個(gè)函數(shù)類型的參數(shù)。我們會(huì)在num1AndNum2()函數(shù)中對(duì)傳入的兩個(gè)整型參數(shù)進(jìn)行某種運(yùn)算纲爸,并返回最終的運(yùn)算結(jié)果亥鸠,但是具體進(jìn)行什么運(yùn)算是由傳入的函數(shù)類型參數(shù)決定的。具體num1AndNum2()的實(shí)現(xiàn)和調(diào)用方法如下所示:
//高階函數(shù)
fun num1AndNum2(num1: Int, num2: Int, operation: (Int, Int) -> Int): Int {
return operation(num1, num2)
}
fun plus(num1: Int, num2: Int): Int {
return num1 + num2
}
fun minus(num1: Int, num2: Int): Int {
return num1 - num2
}
fun main() {
val num1 = 200;
val num2 = 100;
val result1 = num1AndNum2(num1, num2, ::plus)
val result2 = num1AndNum2(num1, num2, ::minus)
println("result1 is $result1") //輸出結(jié)果為:result1 is 300
println("result2 is $result2") //輸出結(jié)果為:result2 is 100
}
這里調(diào)用num1AndNum2()函數(shù)時(shí)识啦,第三個(gè)參數(shù)使用了::plus和::mius這種寫法负蚊。這是一種函數(shù)引用方式的寫法,表示將plus()和minus()函數(shù)作為參數(shù)傳遞給num1AndNum2()函數(shù)颓哮。而由于num1AndNum2()函數(shù)中使用了傳入的函數(shù)類型參數(shù)來決定具體的運(yùn)算邏輯家妆,因此這里實(shí)際上就是分別使用了plus()和minus()函數(shù)來對(duì)這兩個(gè)數(shù)字進(jìn)行運(yùn)算。
上述代碼雖然能夠正常的運(yùn)行冕茅,但是每次調(diào)用的時(shí)候伤极,還得先定義一個(gè)與其函數(shù)類型參數(shù)匹配的函數(shù),這樣太麻煩了姨伤。下面我們利用Lambda表達(dá)式對(duì)其進(jìn)行改寫哨坪,代碼如下所示:
fun main() {
val num1 = 200
val num2 = 100
val result1 = num1AndNum2(num1, num2) { n1, n2 ->
n1 + n2
}
val result2 = num1AndNum2(num1, num2) { n1, n2 ->
n1 - n2
}
println("result1 is $result1") //輸出結(jié)果為:result1 is 300
println("result2 is $result2") //輸出結(jié)果為:result2 is 100
}
看起來是是不是如此優(yōu)美,如此美妙姜挺。
內(nèi)聯(lián)函數(shù)
Java中并沒有高階函數(shù)的概念齿税,所以Kotlin會(huì)對(duì)高階函數(shù)進(jìn)行轉(zhuǎn)換,變成Java編譯器能讀懂的語法結(jié)構(gòu)炊豪。事實(shí)上我們一直使用的Lambda表達(dá)式在底層會(huì)被轉(zhuǎn)換成匿名函數(shù)的形式凌箕。這就說明拧篮,我們每調(diào)用一次Lambda表達(dá)式,都會(huì)創(chuàng)建一個(gè)新的匿名類實(shí)例牵舱,當(dāng)然這樣就必然會(huì)造成額外的內(nèi)存和性能開銷串绩。
為了解決這個(gè)問題,Kotlin提供了內(nèi)聯(lián)函數(shù)的功能芜壁,它可以把Lambda表達(dá)式帶來的運(yùn)行時(shí)開銷完全消除掉礁凡。
inline
內(nèi)存函數(shù)的用法非常簡(jiǎn)單,只需要在高階函數(shù)上加上inline
關(guān)鍵字聲明就可以慧妄,具體如下所示:
inline fun num1AndNum2(num1: Int, num2: Int, operation: (Int, Int) -> Int): Int {
return operation(num1, num2)
}
使用內(nèi)聯(lián)函數(shù)后顷牌,Kotlin編譯器會(huì)將內(nèi)聯(lián)函數(shù)中的代碼在編譯的時(shí)候自動(dòng)替換到調(diào)用它的地方,這樣就不存在運(yùn)行時(shí)的開銷了塞淹。我們對(duì)上面的代碼安裝編譯器的編譯規(guī)則進(jìn)行替換窟蓝,代碼如下所示:
fun main() {
val num1 = 200
val num2 = 100
val result1 = n1 + n2
val result2 = n1 - n2
println("result1 is $result1") //輸出結(jié)果為:result1 is 300
println("result2 is $result2") //輸出結(jié)果為:result2 is 100
}
使用內(nèi)聯(lián)函數(shù)后,如果在lambda表達(dá)式中使用了return關(guān)鍵字饱普,此時(shí)的return代表的是返回最外層的調(diào)用函數(shù)运挫。 而如果不使用內(nèi)聯(lián)函數(shù),lambda表達(dá)式中的return只是表示局部返回套耕,最外層的調(diào)用函數(shù)還是會(huì)繼續(xù)執(zhí)行谁帕。
內(nèi)聯(lián)函數(shù)還有noinline和crossline兩個(gè)關(guān)鍵字,這里就不做詳細(xì)介紹了冯袍,遇到時(shí)請(qǐng)自行搜索匈挖。