高阶函数指以另一个函数或 lambda 表达式为参数或返回值类型的函数
调用时与调用普通函数一样。
fun main(args: Array<String>) {
test { println("aaa${it}") }
}
// 声明 a 为函数类型
fun test(a:(Int)->Unit){
a(11) // 调用 a 函数
}
作为返回值
需要指定函数类型作为返回值类型。下例中 test 函数声明了一个函数类型做为返回值 —— 该函数接收 Int 类型参数,并返回 String。因此 test(1) 后可以直接使用 () 调用返回的函数。
fun main(args: Array<String>) {
println(test(1)(222)) // a = 222
println(test(3)(333)) // else
}
fun test(a:Int):(Int)->String{
return when(a){
1-> {a:Int->"a = ${a}"}
else->{b:Int->"else"}
}
}
内联函数
使用 inline 修饰的函数是内联函数 —— 函数体会被替换到函数被调用的地方,而不是正常的调用
内联时,内联函数和已知具体内容的 lambda 都会被内联。
函数的声明不会被复制,只复制函数的函数体内容。在 java 中也不可能在一个函数内部定义另一个函数。
如下面定义了一个内联函数 sync 以及其使用函数 foo:
// 使用 inline 声明一个内联函数
inline fun <T> synchronized(lock: Lock, action: () -> T): T {
lock.lock()
try {
return action()
}
finally {
lock.unlock()
}
}
// 内联函数的使用者
fun foo(l: Lock) {
println("Before sync")
synchronized(l) {
println("Action")
}
println("After sync")
}
其编译后的代码如下:
可以发现将 sync 函数中的内容完全复制到调用的地方,包括传给 sync 的 lambda 表达式的内容也内联到调用者中。
说明
在上述代码中,调用 sync 时,lambda 表达式的内容是已知的,所以可以将表达式与 sync 函数一起被内联。
但如果调用内联函数时,不知道 lambda 的具体内容,则只能内联内联函数 —— 即只复制 sync 函数的内容,无法复制 lambda 的内容。如下,调用 sync 时只是复制了 sync 的代码,其中 lambda 表达式的内容并没有复制,这是因为在调用时无法确定表达式的具体内容:
class LockOwner(val lock: Lock) {
fun runUnderLock(body: () -> Unit) {
synchronized(lock, body)
}
}
class LockOwner(val lock: Lock) {
fun __runUnderLock__(body: () -> Unit) {
lock.lock()
try {
body() // body 是外界传入的,无法确定内容,所以此处不复制 body 的内容
} finally {
lock.unlock()
}
}
}
内联限制
并不是所有的 lambda 表达式都可以被内联。
如果 lambda 表达式在某个地方被保存起来,以便后面继续使用,表达式则不能被内联。同时会提示
Illegal usage of inline-parameter.
。可以使用
noinline
修饰 lambda 参数,以表示该 lambda 不进行内联。
内联使用
内联函数只能提升带有 lambda 参数的函数的性能。对于其余的函数,内联无能为力。
内联函数必须非常小。如果函数很大,那么将函数复制到各个调用点,将会极大增加字节码的长度。
匿名函数
匿名函数与普通函数相似,除了 省略函数名及参数类型。
匿名函数的 return 语句从匿名函数中返回,而不是从包含匿名函数的函数中返回。
return 从最近使用 fun 关键字声明的函数返回。因此,匿名函数的 return 返回匿名函数,而 lambda 表达式的 return 返回调用 return 的函数。
- 匿名函数是 lambda 的另一种语法。因此,lambda 被内联时的限制一样适用于匿名函数。