- Lambda 表達(dá)式標(biāo)準(zhǔn)語(yǔ)法格式
- 使用Lambda 表達(dá)式
- Lambda 表達(dá)式簡(jiǎn)化寫(xiě)法
- ??參數(shù)類(lèi)型推導(dǎo)簡(jiǎn)化
- ??使用尾隨 Lambda 表達(dá)式
- ??省略參數(shù)聲明
- Lambda 表達(dá)式與 return 語(yǔ)句
??Lambda 表達(dá)式是一種匿名函數(shù),可以作為表達(dá)式、函數(shù)參數(shù) 和 函數(shù)返回值 使用键耕。
一、Lambda 表達(dá)式標(biāo)準(zhǔn)語(yǔ)法格式
??Lambda 表達(dá)式的語(yǔ)法很靈活勺美,下面只是它的標(biāo)準(zhǔn)語(yǔ)法格式:
{ 參數(shù)列表 ->
Lambda 體
}
??Lambda 表達(dá)式的參數(shù)列表與函數(shù)的參數(shù)列表形式類(lèi)似,但是 Lambda 表達(dá)式參數(shù)列表前后 沒(méi)有小括號(hào)() 。箭頭符號(hào)將參數(shù)列表和 Lambda 體分隔開(kāi)养盗,Lambda 表達(dá)式不需要聲明返回類(lèi)型昂利。Lambda 表達(dá)式可以有返回值届腐,如果 沒(méi)有 return 語(yǔ)句,Lambda 體的最后一個(gè)表達(dá)式就是 Lambda 表達(dá)式的返回值蜂奸;如果 有 return 語(yǔ)句犁苏,返回值是 return 語(yǔ)句后面的表達(dá)式。
fun calculate(opr: Char): (Int, Int) -> Int = when (opr) {
'+' -> { a: Int, b: Int -> a + b } // Lambda表達(dá)式
'-' -> { a: Int, b: Int -> a - b } // Lambda表達(dá)式
'*' -> { a: Int, b: Int -> a * b } // Lambda表達(dá)式
else -> { a: Int, b: Int -> a / b } // Lambda表達(dá)式
}
fun main(args: Array<String>) {
val f1 = calculate('+')
println(f1(10, 5)) // 15
val f2 = calculate('-')
println(f2(10, 5)) // 5
val f3 = calculate('*')
println(f3(10, 5)) // 50
val f4 = calculate('/')
println(f4(10, 5)) // 2
}
??上面代碼fun calculate(opr: Char)
后面的(Int, Int) -> Int
是返回值類(lèi)型(函數(shù)類(lèi)型)扩所,而不是 Lambda 表達(dá)式围详。
??提示:Lambda 表達(dá)式與函數(shù)、匿名函數(shù)一樣都有函數(shù)類(lèi)型祖屏,但從 Lambda 表達(dá)式的定義中只能看到參數(shù)類(lèi)型短曾,看不到返回類(lèi)型聲明,那是因?yàn)榉祷仡?lèi)型可以通過(guò)上下文推導(dǎo)出來(lái)赐劣。
二嫉拐、使用Lambda 表達(dá)式
??Lambda 表達(dá)式也是函數(shù)類(lèi)型,可以聲明變量魁兼,也可以作為其他函數(shù)的參數(shù)或者返回值使用婉徘。
fun calculatePrint(a: Int, b: Int, opr: Char, func: (Int, Int) -> Int) {
println("$a $opr $b = ${func(a, b)}")
}
fun main(args: Array<String>) {
calculatePrint(10, 5, '+', { a, b -> a + b }) // Lambda作為參數(shù)
calculatePrint(10, 5, '-', func = { a, b -> a - b }) // Lambda作為參數(shù)(命名參數(shù)方式傳參)
}
三、Lambda 表達(dá)式簡(jiǎn)化寫(xiě)法
??kotlin 提供了多種 Lambda 表達(dá)式的簡(jiǎn)化寫(xiě)法咐汞。
1盖呼、??參數(shù)類(lèi)型推導(dǎo)簡(jiǎn)化
??kotlin 編譯期可以根據(jù)上下文環(huán)境推導(dǎo)出參數(shù)類(lèi)型和返回值類(lèi)型。例如上面代碼定義的高階函數(shù) calculate(opr: Char) 返回值類(lèi)型為 (Int, Int) -> Int
化撕,下面給出此高階函數(shù)的 Lambda 表達(dá)式的標(biāo)準(zhǔn)版 和 簡(jiǎn)化版:
// 標(biāo)準(zhǔn)類(lèi)型的Lambda表達(dá)式
{ a: Int, b: Int -> a + b}
??kotlin 可以根據(jù)高階函數(shù)calculate的返回值類(lèi)型(Int, Int) -> Int
几晤,推斷出 Lambda 表達(dá)式參數(shù)為 Int 類(lèi)型,返回值類(lèi)型也為 Int 類(lèi)型植阴。
// 簡(jiǎn)化版
{ a, b -> a + b}
??完整的簡(jiǎn)化版 calculate 代碼:
fun calculate(opr: Char): (Int, Int) -> Int = when (opr) {
'+' -> { a, b -> a + b }
'-' -> { a, b -> a - b }
'*' -> { a, b -> a * b }
else -> { a, b -> a / b }
}
2蟹瘾、??使用尾隨 Lambda 表達(dá)式
??如果一個(gè)函數(shù)的最后一個(gè)參數(shù)是 Lambda 表達(dá)式,那么這個(gè) Lambda 表達(dá)式可以放到函數(shù)括號(hào)之后掠手。
fun calculatePrint(a: Int, b: Int, opr: Char, func: (Int, Int) -> Int) {
println("$a $opr $b = ${func(a, b)}")
}
fun calculatePrint105(func: (Int, Int) -> Int) {
println("${func(10, 5)}")
}
fun main(args: Array<String>) {
// 標(biāo)準(zhǔn)調(diào)用
calculatePrint(10, 5, '+', { a, b -> a + b })
calculatePrint105({ a, b -> a + b })
// 尾隨Lambda表達(dá)式
calculatePrint(10, 5, '+') { a, b -> a + b } // 1??
calculatePrint105() { a, b -> a + b } // 2??
// calculatePrint105(){a, b -> a + b} 再簡(jiǎn)化版本
calculatePrint105 { a, b -> a + b } // 尾隨Lambda表達(dá)式憾朴,如果沒(méi)有參數(shù)可以省略括號(hào)
}
??注意:尾隨 Lambda 表達(dá)式容易被誤認(rèn)為是函數(shù)聲明,如上述代碼第1??喷鸽、2??行众雷,是不是會(huì)認(rèn)為是一個(gè)函數(shù)?但它缺少函數(shù)聲明的必要關(guān)鍵字 fun,同時(shí)也缺少參數(shù)類(lèi)型砾省,命名規(guī)定等鸡岗。
3、??省略參數(shù)聲明
??如果 Lambda 表達(dá)式的參數(shù)只有一個(gè)编兄,并且能夠根據(jù)上下文環(huán)境推導(dǎo)出它的數(shù)據(jù)類(lèi)型纤房,那么這個(gè)參數(shù)聲明可以省略,在 Lambda 體中使用隱式參數(shù) it 替代 Lambda 表達(dá)式的參數(shù)翻诉。
fun reversePrint(word: String, func: (String) -> String) {
println("${func(word)}")
}
fun main(args: Array<String>) {
// 未省略參數(shù)說(shuō)明
reversePrint("hello") { word -> word.reversed() }
// 省略參數(shù)說(shuō)明
reversePrint("hello") { it.reversed() }
val result1: (String) -> Unit = { print(it) } // 3??省略參數(shù)說(shuō)明,并且可以根據(jù)result1聲明的函數(shù)類(lèi)型捌刮,判斷出隱式參數(shù)it的類(lèi)型
val result2 = { a: String -> print(a) } // 4??不能省略參數(shù)說(shuō)明碰煌,無(wú)法根據(jù)上下環(huán)境判斷出參數(shù)類(lèi)型
}
??注意:Lambda體中 it 隱式變量是由 kotlin 編譯器生成的,它的使用有兩個(gè)前提:一是 Lambda 表達(dá)式只有一個(gè)參數(shù)绅作,二是根據(jù)上下文環(huán)境能夠推導(dǎo)出參數(shù)類(lèi)型芦圾。比較代碼第3??、4??行會(huì)發(fā)現(xiàn)俄认,代碼第4??行由于 result2 沒(méi)有指定數(shù)據(jù)類(lèi)型个少,編輯器不能推導(dǎo)出 Lambda 表達(dá)式的參數(shù)類(lèi)型,所以不能使用 it眯杏。而代碼第3??行夜焦,由于 result1 指定了數(shù)據(jù)類(lèi)型為 (String) -> Unit,編輯器能夠推導(dǎo)出 Lambda 表達(dá)式的參數(shù)類(lèi)型岂贩,所以可以使用 it茫经。
四、Lambda 表達(dá)式與 return 語(yǔ)句
??Lambda 表達(dá)式可以使用 return 語(yǔ)句萎津,它會(huì)使程序跳出 Lambda 表達(dá)式體卸伞;
??例如:函數(shù) sum 內(nèi)部有一個(gè) Lambda 表達(dá)式,在 Lambda 表達(dá)式內(nèi)執(zhí)行 return 語(yǔ)句锉屈,則會(huì)直接結(jié)束 sum 函數(shù)荤傲,而 return語(yǔ)句的返回值,作為了 sum 函數(shù)的返回值颈渊。
fun sum(vararg num: Int): Int {
var total = 0
num.forEach {
if (it == 10) return -1
total += it
}
return total
}
fun main(args: Array<String>) {
val n = sum(1, 2, 10, 3)
println(n)
}
2019-06-05 12:48:22.000 17599-17599/cn.ak.kot I/System.out: -1
??那么像上面的代碼能通過(guò) return 結(jié)束 Lambda 表達(dá)式嗎遂黍?當(dāng)然是可以的,但需要在 return 時(shí)指定返回標(biāo)簽俊嗽,返回標(biāo)簽用法在Kotlin基礎(chǔ)認(rèn)識(shí) (8)程序流程控制中有介紹妓湘。修改后的代碼如下:
fun sum(vararg num: Int): Int {
var total = 0
num.forEach {
if (it == 10) return@forEach // 5??@forEach是隱式聲明標(biāo)簽
total += it
}
return total
}
fun main(args: Array<String>) {
val n = sum(1, 2, 10, 3)
println(n)
}
2019-06-05 14:18:09.269 22302-22302/cn.ak.kot I/System.out: 6
??上述代碼第5??行是使用隱式標(biāo)簽 @forEach 結(jié)束本次 Lambda 表達(dá)式運(yùn)行。
??提示:forEach 是集合乌询、數(shù)組或區(qū)間的函數(shù)榜贴,它后面是一個(gè) Lambda 表達(dá)式,集合、數(shù)組或區(qū)間對(duì)象調(diào)用 forEach 函數(shù)時(shí)唬党,會(huì)將它們的每一個(gè)元素傳遞給 Lambda 表達(dá)式并執(zhí)行鹃共。
??下面是一個(gè)顯示使用標(biāo)簽的案例:
fun main(args: Array<String>) {
val add = label@ { // 打一個(gè)標(biāo)簽,標(biāo)記結(jié)束位置
val a = 1
val b = 2
return@label 10 // 結(jié)束運(yùn)行驶拱,返回到標(biāo)簽位置
a + b // 這句代碼實(shí)際是永遠(yuǎn)執(zhí)行不到的
}
println(add())
}
2019-06-05 14:25:10.968 23002-23002/cn.ak.kot I/System.out: 10