在高阶函数中参数如果是函数类型, 则可以接收 Lambda 表达式,而Lambda表达式在编译时被编译成为一个匿名类,每次调用函数时都会创建一个对象,如果被函数反复调用则创建很多对象,会带来运行时的额外开销。为了解决此问题,在 kotlin 中可以将这种函数声明为内联函数。
提示:内联函数在编译时不会生成函数调用代码,而是用函数体中的实际代码替换每次的调用函数。
一、自定义内联函数
kotlin 中如果函数参数不是函数类型,不能接收 Lambda 表达式,那么这种函数一般不声明为内联函数。声明内联函数需要使用关键字 inline 修饰。
二、使用 let 函数
let 扩展函数的实际上是一个作用域函数,当你在特定的作用域范围内需要定义一个变量,那么使用 let 会是一个很好的选择;
let 函数的另一个常见使用场景是可以避免一些 null 的判断。
let 函数底层的 inline扩展函数 + lambda 表达式结构,查看源码同样可以提高理解和开发使用,同时也能让我们在开发过程当中写出类似函数
从源码看let函数是T类型对象的扩展函数,它只有一个参数block,类型为(T) ->R的lambda表达式,而this作为block(this)的参数传递给lambda表达式,所以在let函数体内可以通过it指代该T对象,返回值为lambda函数体的最后一行或指定return表达式。
let 的使用,为了更直观的学习,看一下 Android 中一个简单使用示例:
三、使用 with 函数
先看with 函数常见使用结构
with(object){
this.todo()// this指代object对象
...// 最后一行表达式,为函数with的返回值
}
with 函数底层的 inline函数 + lambda 表达式结构
从源码可以看出with函数并不是一个扩展函数。它是将T对象实例和类型T.() -> R的lambda作为函数参数,而T.() -> R类型的lambda函数体内的this指向是对象T的实例,所以在lambda表达式体内可以直接访问T对象的函数和属性,返回值为lambda函数体的最后一行或指定return表达式。
四、使用 apply 函数
apply 函数常见使用结构,返回值固定为调用对象本身。
apply 函数底层的 inline扩展函数 + lambda 表达式结构
从源码看apply函数是T类型对象的扩展函数,它接受的参数是T.() -> Unit的lambda表达式,所以lambda函数体内的this指向是对象T实例,所以在lambda表达式体内可以直接访问T对象的函数和属性,返回值是Unit说明lambda表达式是没有返回值的,但apply这个高级函数是有返回值的,它的返回值是this,也就是调用者本身。
五、内联扩展函数之run
run函数使用的一般结构
run函数的inline+lambda结构
run函数的inline结构分析
run函数实际上可以说是let和with两个函数的结合体,run函数只接收一个lambda函数为参数,以闭包形式返回,返回值为最后一行的值或者指定的return的表达式。