inline 主要用于展开铺平函数,用于高频访问但是代码不是很多的方法,减少函数对象的定义
fun <T> List<T>.normalForeach(action:(T)->Unit){
for(item in this){
action(item)
}
}
inline fun <T> List<T>.inlinedForeach(action: (T) -> Unit){
for(item in this){
action(item)
}
}
inline就好像把函数内部的代码拷贝一份到调用的地方,减少了函数对象的中间产生。
带来的变化是,可以非本地的返回
fun main(){
val list = (1..100).toList()
list.normalForeach {
println(it)
return@normalForeach
}
list.inlinedForeach {
println(it)
return
}
}
普通的函数只能返回 return@normalForeach
内敛函数,因为相当于被拷贝过来了,可以直接返回到main,
另外内敛带来的变化还有
fun main(){
val list = (1..100).toList()
CoroutineScope(Dispatchers.Default).launch {
delay(1000)
list.normalForeach {
println(it)
delay(1000) //错误!非内敛,无scope环境
return@normalForeach
}
list.inlinedForeach {
println(it)
delay(1000)
return@launch
}
}
}
我们启动了一个协程,但是在normalForeach的lambda中无法使用delay,因为这里其实是一个函数对象,会指向到另外一个函数方法,没有协程的上下文环境,但是内敛函数就不一样了,他相当于是把lambda中的内容拷贝平铺过来了,所以,在inlinedForeach中可以使用协程的上下文环境,delay可以执行。
但是当一个函数被声明为内敛函数的时候,只能直接的运行函数参数,或者在另外一个内敛函数中运行函数参数,
inline fun <T> List<T>.inlinedForeach(action: (T) -> Unit){
for(item in this){
action(item) //直接运行方法参数
kotlin.run {
action(item) //或者在另外一个内敛函数中运行
}
Thread{
action(item) //报错!不可以跨scope或者context
}
}
}
那如果我们必须要参数中的函数可以切换调用呢?
那我们需要在函数参数上crossinline关键字,允许函数被跨上下文调用
inline fun <T> List<T>.inlinedForeach(crossinline action: (T) -> Unit){
for(item in this){
action(item) //直接运行方法参数
kotlin.run {
action(item) //或者在另外一个内敛函数中运行
}
Thread{
action(item) //因为crossinline关键字,不报错了
}
}
}
这样,就可以在Thread中调用action了,但是因为函数参数被声明了crossinlne,原本的非本地返回就不可以用了
所以要不要非本地返回和跨上下文调用,只能二选一
另外,当把一个函数声明为inline的时候,他的lambda参数也是inline的,所以无法通过函数地址引用的方式来调用
但是我们需要再inline声明的函数参数中,通过地址的方式来引用的话,就要noinline来声明
inline fun <T> List<T>.inlinedForeach(
crossinline action: (T) -> Unit,
noinline onError: (Exception) -> Unit
) {
try {
for (item in this) {
action(item) //直接运行方法参数
kotlin.run {
action(item) //或者在另外一个内敛函数中运行
}
Thread {
action(item) //因为crossinline关键字,不报错了
}
}
} catch (e: Exception) {
e.printStackTrace()
handleError(e,onError)
}
}
fun handleError(exception: java.lang.Exception,onError: (Exception) -> Unit) {
println("handle ")
onError(exception)
}