这一篇看下crossinline,同样他也要在inline函数中才能使用
先来看下这样2种情况
情况1:
fun mainInline2(func1: () -> Unit) {
func1()
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
mainInline2 {
print("return")
return //编译会报错,不允许使用return
}
}
这是一个常规的函数如果func1的函数体包含return是不允许的,但是如果我们按照他可以允许的逻辑来看,这个return应该返回的是func1函数。
情况2:
inline fun mainInline2(func1: () -> Unit) {
func1()
}
其他的不变,我们将mainInline2声明为inline函数,这时候是可以在func1函数内部使用return的,但是由于这是内联函数,调用处就是这样
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.setContentView(1300009);
int $i$f$mainInline2 = false;
int var4 = false;
String var5 = "return";
boolean var6 = false;
System.out.print(var5);
return //为了形象描述 自己添加的,原字节码没有这行
}
从前面的文章知道,内联函数会将函数体直接复制到调用处,所以这个return返回的就是外部的onCreate函数
如果2种情况都是允许的话,会出现一个情况,我们调用一个函数,如果内部有return,返回的到底是哪个函数呢,是与return临近的函数还是最外部的,这个得看是内联函数还是普通函数。
(但是我们也不能每次调用一个函数都去看一下他是普通函数还是内联函数)所以Kotlin的规定就是:
只有内联函数的函数类型参数内部可以有return 也就是上面的情况2中的func1能有return (但是都可以使用return@xxx,即带标签的return语句,等于明确指定了返回地方),也就是普通函数里面有函数参数的,这个函数参数内部直接不允许return,那这样就只剩下一种情况了,(普通函数无返回,内联函数返回到最外层函数)消除了歧义
接下来再说到crossinline,我们再将上面的函数改一下
inline fun mainInline2(func1: () -> Unit) {
runOnUiThread {
func1() //编译器报错
}
}
我们在内联函数中添加一个runOnUiThread,然后在他内部调用func1函数,编译器报错,会提醒func1可能包含这非当前返回的return,
原因:这样就有可能触发了之前的规则,普通函数的函数参数不允许带有return(为什么说是可能,因为现在编译器也不知道func1的内部会不会带有return),所以会直接提示可能含有return而报错,如果想这样去间接调用,我们就需要加上crossinline,加上了crossinline,就直接不允许func1内部包含return,本质:crossinline的功能就相当于让编译器帮我们做检查,让我们编写函数参数体的时候,当我们写了return,直接提醒我们这里不能写return。这样编译器就不会在报错提醒怀疑func1内部会有return,crossinline加上后,编译器直接禁止写return,如果写了return,在IDE就会立即看到报错。
这个问题触发的重点是 有非inline函数间接调用(runOnUiThread是非inline函数)
inline fun mainInline2(crossinline func1: () -> Unit) {
runOnUiThread {
func1()
}
}
这样就不再报错,这是为啥呢,如果我们在调用mainInline2的时候就会发现
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
mainInline2 {
print("return")
return //报错
}
}
调用的时候,我们在函数体内部加入return发现编译器报错,不允许我们在函数体内加入return,所以也就不存在歧义,因为crossinline直接禁止标记的函数内部包含return。
小结:
- kotlin只允许内联函数的函数参数内部有return,普通函数的函数参数内部不能有return
- crossinline让编译器帮我们检查函数参数内部是不是带有return,有的话直接在IDE提醒我们不能写(还是为了满足结论1,禁止函数参数写return)
针对小结2的示例
//普通函数
fun normalFunc(normalParams: () -> Unit)
inline fun inlineFunc(inlineParams: () -> Unit) {
//不允许这样调用,有可能触发了小结1的规则,inlinePrams内部可能会写return
normal {
inlineParams()
}
}
fun main() {
inlineFunc()
}
}