函数式编程
函数不依赖于任何类存在(从源代码级别上,从字节码层级,它仍然会依赖于类存在)。典型的如顶层函数。
lambda 表达式
lambda 表达式和 java 相同,它由被“箭头”符号(-> )分隔的两个部分组成。箭头左边是括号包裹的参数列表(如果只有一个参数,括号可以省略),箭头右边是返回值类型:
(a: Int, b: Int) -> Int
{ a,b -> a+b }
val add = { a:Int, b:Int -> a+b }
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)
test(2,3, { a,b -> println(a-b)})
test(2,3){ a,b -> println(a-b)}
test { a,b -> println(a-b) }
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")}
test2(5){ println("bbb")}
}
- 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)
test5(5){
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{
return operation(a,b)
}
... ...
println(calculate(2,3){a,b -> a+b})
- calculate 函数的最后一个参数是一个函数(即 lambda 表达式),因此是一个高阶函数。
- 调用 lambda 表达式并返回调用结果。
再看一个例子:
fun String.filter(predicate: (Char,Int) -> Boolean): String {
val i = 0
var result = ""
for(c in this.toCharArray()){
if(predicate(c, i)){
result += c
}
}
return result
}
fun main(args: Array<String>) {
var string = "1324q22ddd"
string = string.filter(){
ch, index -> ch.isDigit()
}
println(string)
}
-
为 String 扩展一个 filter 函数,这个函数是一个高阶函数,以一个 lambda 为参数。这个 lambda 会接受 2 个参数: 一个字符和该字符在字符串中的索引,返回 Boolean 表示是否接受该字符。 -
遍历字符串中每个字符。 -
用这个字符及其索引调用 lambda 表达式,如果表达式返回 true,则在返回结果中包含该字符,否则过滤该字符。 -
遍历结束,返回过滤的结果(一个新的字符串)。 -
调用 filter,用一个 lambda 表达式作为参数,该 lambda 表达式会根据传入的字符进行判断,如果该字符是数字,返回 true,否则返回 false。注意,这里 lambda 表达式最后一个表达式的值,默认会作为 lambda 表达式的返回值,因此不用 return。如果要 return,则需要使用全限定的方式 return。 return@filter ch.isDigit()
|