系列文章全部為本人的學習筆記弟跑,若有任何不妥之處廊蜒,隨時歡迎拍磚指正添寺。如果你覺得我的文章對你有用胯盯,歡迎關注我,我們一起學習進步计露!
Kotlin學習筆記(1)- 環(huán)境配置
Kotlin學習筆記(2)- 空安全
Kotlin學習筆記(3)- 語法
Kotlin學習筆記(4)- 流程控制
Kotlin學習筆記(5)- 類
Kotlin學習筆記(6)- 屬性
Kotlin學習筆記(7)- 接口
Kotlin學習筆記(8)- 擴展
Kotlin學習筆記(8)- 擴展(續(xù))
Kotlin學習筆記(9)- 數據類
Kotlin學習筆記(10)- 泛型
Kotlin學習筆記(11)- 內部類和嵌套類
Kotlin學習筆記(12)- 委托
Kotlin學習筆記(13)- 函數式編程
Kotlin學習筆記(14)- lambda
在上一篇《Kotlin學習筆記(13)- 函數式編程》的最后我提到lambda為函數式編程提供了更多更好的實現(xiàn)博脑,如果你還不太了解什么是函數式編程,那么可以看看我的上一篇文章票罐。那么我們首先來看看什么是lambda叉趣,在百度百科上是這么說的:
“Lambda 表達式”(lambda expression)是一個匿名函數,Lambda表達式基于數學中的λ演算得名该押,直接對應于其中的lambda抽象(lambda abstraction)疗杉,是一個匿名函數,即沒有函數名的函數蚕礼。Lambda表達式可以表示閉包(注意和數學傳統(tǒng)意義上的不同)烟具。
一、Lambda的定義
看上面的說法有點抽象奠蹬,有點不明所以朝聋,我們先來看一個栗子
class Num {
fun logic(a: Int, b: Int, calc: (Int, Int) -> Int){
println("calc : ${calc(a,b)}")
}
}
fun main(args : Array<String>){
val num = Num()
num.logic(1, 2, {x,y -> x+y})
}
// 輸出
calc : 3
這個栗子和上一篇文章很像,只是在調用的時候改成了Lambda方式:num.logic(1, 2, {x,y -> x+y})
囤躁,其中{x,y -> x+y}
就是我們今天要講的Lambda表達式冀痕,它的完整格式應該是這樣
{ x: Int, y: Int -> x + y }
寫成java代碼是這個樣子:
public int sum(int x, int y){
return x+y;
}
可以很明顯看出有幾個規(guī)則:
- 參數寫在
->
左邊,格式與普通函數的參數格式一樣狸演,多個參數用逗號,
分割 - 參數的類型可選言蛇,可忽略,編輯器會根據上下文推斷(這就和普通函數不一樣了吧宵距,有種“我知道你懂得猜极,所以就不寫了”的感覺有木有,知己的感覺啊……)
- 函數體跟在
->
右邊 - Lambda表達式總是被大括號
{}
包圍著
二消玄、Lambda中的一些約定
-
如果 Kotlin 可以自己計算出簽名跟伏,它允許我們不聲明唯一的參數,并且將隱含地為我們聲明其名稱為
it
翩瓜。其實通常情況下它都可以自己計算出簽名受扳,也就是說,如果函數字面值只有一個參數兔跌, 那么它的聲明可以省略(連同->
)板熊,其名稱是it
fun oneParams(one : (Int) -> Int){ println("oneParams : ${one(5)}") } fun main(args : Array<String>){ val num = Num() num.oneParams({it * 2}) } // 輸出 oneParams : 10
說到省略,其實還有一種情況可以省略
->
项钮,大家應該也能想到,就是無參函數蕊蝗。fun empty(emptyM : () -> Unit){ emptyM() } fun main(args : Array<String>){ val num = Num() num.empty({println("empty method")}) } // 輸出 empty method
-
如果Lambda中的某個參數沒有用到,可以用下劃線
_
代替赖舟,也就是說蓬戚,省了好多請名字的腦細胞有木有!這個特性從1.1開始可以使用宾抓,現(xiàn)在你看到的時候應該已經不止1.1了吧子漩,所以這個限制看看就好~fun unusedParams(unused : (Int,Int) -> Int){ println("unusedParams : ${unused(5,10)}") } fun main(args : Array<String>){ val num = Num() num.unusedParams { _, used -> used * 2 } } // 輸出 unusedParams : 20
-
如果函數的最后一個參數是一個函數,那么我們在用Lambda表達最后一個函數參數的時候石洗,可以把它放在括號
()
外面幢泼,所以下面的寫法是等價的。class Num { fun logic(a: Int, b: Int, calc: (Int, Int) -> Int){ println("calc : ${calc(a,b)}") } fun sum(a: Int, b: Int) = a + b } fun main(args : Array<String>){ val num = Num() // 寫法1 num.logic(1, 2, {x : Int,y : Int -> x+y}) // 寫法2 num.logic(1, 2){x : Int,y : Int -> x+y} // 寫法3 num.logic(1, 2){x,y -> x+y} }
那么這么寫有什么好處呢讲衫?難道只是位置變了一下缕棵?當然不是,不要忘記涉兽,Lambda的
->
后面是方法體挥吵,也就是很多時候不是想栗子中這樣只有一行,如果有多行的話花椭,體會一下他們的區(qū)別:num.logic(1, 2, {x,y -> println("extra line") x+y }) num.logic(1, 2){x,y -> println("extra line") x+y }
是不是感覺下面的寫法要優(yōu)雅很多忽匈,也明確很多?
-
其實在上面一點應該已經能看出矿辽,如果有需要的話丹允,Lambda會隱式的返回最后一個表達式的值,就像上面的最后一行
x+y
袋倔。當然雕蔽,我們也可以顯示的表達返回值,下面的寫法還是一樣的:// 寫法1 num.unusedParams { _, used -> println("print first") return@unusedParams used * 2 } // 寫法2 num.unusedParams { _, used -> println("print first") used * 2 }
三宾娜、匿名函數
看了這么多批狐,我們發(fā)現(xiàn)一個問題,Lambda的返回類型全是自動推斷的前塔,雖然很人性化嚣艇,但是有時候我們就是想自己指定類型怎么辦?當然是有辦法的华弓,那就是匿名函數食零。
fun(x:Int, y:Int):Int{return x+y}
匿名函數看起來非常像一個常規(guī)函數聲明,除了其名稱省略了寂屏。其函數體可以是表達式(如上所示)或代碼塊贰谣。由于這已經不算正經的Lambda娜搂,所以它不需要被大括號{}
包裹,也不能像Lambda一樣寫在括號()
外吱抚,而調用也是直接調用百宇。
num.logic(1, 2, fun(x:Int, y:Int):Int{return x+y})
四、閉包
Lambda 表達式或者匿名函數(以及局部函數和對象表達式) 可以訪問其 閉包 秘豹,即在外部作用域中聲明的變量携御。 與 Java 不同的是可以修改閉包中捕獲的變量:
var sum = 0
ints.filter { it > 0 }.forEach {
sum += it
}
print(sum)
五、小結
其實沒什么小結憋肖,關于更多的函數式的高級應用因痛、復雜應用婚苹,個人也正在學習岸更,大家互相交流。