深入kotlin - lambda 表达式和高阶函数
Posted 颐和园
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了深入kotlin - lambda 表达式和高阶函数相关的知识,希望对你有一定的参考价值。
函数式编程
函数不依赖于任何类存在(从源代码级别上,从字节码层级,它仍然会依赖于类存在)。典型的如顶层函数。
lambda 表达式
lambda 表达式和 java 相同,它由被“箭头”符号(->
)分隔的两个部分组成。箭头左边是括号包裹的参数列表(如果只有一个参数,括号可以省略),箭头右边是返回值类型:
// 定义 lambda 表达式的类型
(a: Int, b: Int) -> Int
// 定义 lambda 表达式实例
a,b -> a+b // 花括号包裹,不能省略
// 利用 lambda 实例推断出 lambda 的类型
val add = a:Int, b:Int -> a+b
// 无参数,无返回值(或者返回 Unit)
val action = println("hello")
// 允许函数为空
val action: ((Int,Int) -> Int)? = null
lambda 表达式作为参数
fun substract(a:Int, b: Int) = println(a-b)
fun test(a: Int = 1, b: Int = 2, compute: (x:Int, y:Int)->Unit)
compute(a,b)
... ...
test(2,3,::substract) // 1
test(2,3, a,b -> println(a-b)) // 2
test(2,3) a,b -> println(a-b) // 3
test a,b -> println(a-b) // 4
compute 参数是一个 lambda 表达式,接收两个参数,返回 Unit(即 void,无返回值)。
- 这里将一个 方法引用(java8)传递给 compute 参数。方法引用的形式为
类名::方法名
,这里 substract 是顶层对象,没有类名,所以类名省略。 - 直接传递 lambda 表达式。注意,
a,b
参数列表不需要用括号包裹。 - 尾随闭包写法。
- 使用默认参数的写法,注意,包括方法参数的括号可以省略,同时,尾随闭包不需要指定参数名。
lambda 表达式的参数
fun test(x: Int, action:()-> Unit)
fun test2(x: Int, action:(Int)->Unit)
fun main()
test(5) println("aaa") // 1
test2(5) println("bbb") // 2
- test 的 action 参数是一个不带参数的lambda,所以调用时不用声明任何 lambda 的参数。
- Test2 的 action 参数是有参数的 lambda,但在调用时同样可以不声明任何 lambda 参数。这是 kotlin 的一种语言特性,如果方法的 lambda 表达式只有一个参数,那么在调用时可以忽略,如果你要使用到这个参数,可以用隐含参数(it 关键字) 来引用。
fun test3()
fun test4(x:Int)
fun test5(x:Int, action:(Int,Int)->Unit)
action(1,2)
fun test6(x:Int, y:Int) println(x+y)
fun main()
test(5, ::test3)
test2(5, ::test4)
test5(5, ::test6) // 1
test5(5) // 2
println("a")
- 将 test 6 的函数引用传递给 test5 的第二个参数。这样 test5 的唯一一句: action(1,2) 就变成了 test6(1,2) ,结果打印出:3。
- 编译错误。因为 test5 的 action 需要两个参数,lambda 表达式的参数就不能省略了,必须声明。
高阶函数
接收一个函数作为参数或者将一个函数作为返回值的函数,被称作高阶函数。如果一个函数的最后一个参数是函数,那么可以用 lambda 尾随闭包形式。Kotlin 中,lambda 表达式就是函数。
fun calculate(a:Int, b:Int, operation: (Int, Int)->Int): Int // 1
return operation(a,b) // 2
... ...
println(calculate(2,3)a,b -> a+b)
- calculate 函数的最后一个参数是一个函数(即 lambda 表达式),因此是一个高阶函数。
- 调用 lambda 表达式并返回调用结果。
再看一个例子:
fun String.filter(predicate: (Char,Int) -> Boolean): String // 1
val i = 0
var result = ""
for(c in this.toCharArray()) // 2
if(predicate(c, i)) // 3
result += c
return result // 4
fun main(args: Array<String>)
var string = "1324q22ddd"
string = string.filter()
ch, index -> ch.isDigit() // 5
println(string) // 打印:132422
-
为 String 扩展一个 filter 函数,这个函数是一个高阶函数,以一个 lambda 为参数。这个 lambda 会接受 2 个参数: 一个字符和该字符在字符串中的索引,返回 Boolean 表示是否接受该字符。
-
遍历字符串中每个字符。
-
用这个字符及其索引调用 lambda 表达式,如果表达式返回 true,则在返回结果中包含该字符,否则过滤该字符。
-
遍历结束,返回过滤的结果(一个新的字符串)。
-
调用 filter,用一个 lambda 表达式作为参数,该 lambda 表达式会根据传入的字符进行判断,如果该字符是数字,返回 true,否则返回 false。注意,这里 lambda 表达式最后一个表达式的值,默认会作为 lambda 表达式的返回值,因此不用 return。如果要 return,则需要使用全限定的方式 return。
return@filter ch.isDigit() // 用 @ 符号显式指定是返回到 filter 而非当前函数
以上是关于深入kotlin - lambda 表达式和高阶函数的主要内容,如果未能解决你的问题,请参考以下文章
深刻理解 Kotlin高阶函数匿名函数以及lambda表达式
深刻理解 Kotlin高阶函数匿名函数以及lambda表达式