+-
Kotlin 高阶函数与内联函数

一、前言

<font face= 黑体>在 Kotlin 学习笔记之内置类型(2)中我们已经将 Kotlin 函数的基本概念基本用法讲完了,今天我们来讲函数进阶

二、高阶函数

2.1、高阶函数概念

<font face= 黑体>高阶函数就是参数类型包含函数类型或者返回值类型是函数类型的函数,简单的说,高阶函数就是函数里面套函数,如下所示:

// 参数类型是函数类型
fun needsFunction(block: () -> Unit) {
    block()
}

// 返回值是函数类型
fun returnsFunction(): () -> Long {
    return {System.currentTimeMillis()}
}

2.2、常见的高阶函数

<font face= 黑体>forEach 函数: 接受的参数是一个函数

// Kotin 自带的 forEach 函数
inline fun IntArray.forEach(action: (Int) -> Unit): Unit {
    for (element in this) action(element)
}

<font face= 黑体>map 函数: 接受的参数是一个函数

// Kotin 自带的 map 函数
inline fun <R> IntArray.map(transform: (Int) -> R): List<R> {
    return mapTo(ArrayList<R>(size), transform)
}

2.3、高阶函数的调用

<font face= 黑体>forEach 的调用:

val intArray = IntArray(5){ it + 1 }

intArray.forEach(::println)

// 括号() 里面其实可以把它当做一个参数,只是这个参数是函数
intArray.forEach ({
    println(it)
})

// () 可以省略,就变成了下面这样
intArray.forEach {
    println(it)
}
<font face= 黑体>forEach 接受的类型参数类型是 (Int) -> Unit,而 println 函数的类型有一个就是 (Int) -> Unit,所以可以用函数引用来接收。

三、内联函数

3.1、内联函数概念

<font face= 黑体>被 inline 标记的函数就是内联函数,其原理就是:在编译时期,把调用这个函数的地方用这个函数的方法体进行替换。我们来看下面这个代码,就是一个 forEach 函数遍历数组:

val ints = intArrayOf(1, 2, 3, 4)
ints.forEach {
    println("Hello $it")
}

<font face= 黑体>forEach 函数的定义上面我们已经看到了,如下,可以看到,forEach 被 inline 修饰,所以它是个内联函数

inline fun IntArray.forEach(action: (Int) -> Unit): Unit {
    for (element in this) action(element)
}

<font face= 黑体>其实 forEach 真正的实现是下面这个代码:

for (element in this) action(element)

<font face= 黑体>内联函数可以减少函数的调用来优化性能。

3.2、内联函数的定义

<font face= 黑体>内联函数的定义很简单,就是在一个函数的前面加上 inline 关键字。

inline fun hello() {
    println("hello")
}

<font face= 黑体>虽然说内联函数可以减少函数的调用来优化性能,但是并不是每个函数前加一个 inline 就可以优化性能,其实我们一般会把高阶函数定义为内联函数。

3.3、高阶函数与内联函数更配

cost {
    println("hello")
}
inline fun cost(block: () -> Unit) {
    val start = System.currentTimeMillis()
    block()
    println(System.currentTimeMillis() - start)
}

<font face= 黑体>比如说我们要计算 println("hello") 这段代码执行的时间,如果不加 inline 的话,那么调用 cost 就要创建 Lambda 表达式,函数调用,结果发现这些操作的时间就要大于 println("hello") 这段代码执行的时间,这样是完全没有必要的,所以我们加上 inline 之后,调用 println("hello"),实际上就等于下面这样:

val start = System.currentTimeMillis()
println("hello")
println(System.currentTimeMillis() - start)
<font face= 黑体>可以看到加上 inline 之后,cost 函数的调用开销没了,Lambda 表达式的创建开销也没了,这就是内联函数的作用。

3.4、内联函数的限制

<font face= 黑体>public/protected 的内联方法只能访问对应类的 public 成员; <font face= 黑体>内联函数里面的参数不能被存储(赋值给一个变量); <font face= 黑体>内联函数的参数只能传递给其他内联函数。
<font face= 黑体> 其实内联函数最重要的是对高阶函数的性能优化。

四、小结

<font face= 黑体>本篇博客主要讲了 Kotlin 中的高阶函数内联函数,下一节我们讲 Kotin 的 集合变换与聚合

五、源码

源码 已上传至 github,有需要可以直接下载。