invoke()作为类方法和扩展函数时有什么差别


#1

代码如下:

class B {
    operator fun invoke() {
        println("B invoke")
    }
}
class A(val b: B?) {
//    @Suppress("UNSAFE_CALL")
    fun a() {
        if (b != null) {
            b.invoke()
            b()
        }
    }
}

反编译后的java代码:

   public final void a() {
      if (this.b != null) {
         this.b.invoke();
         this.b.invoke();
      }
   }

上述代码idea会在b()处提示
Only safe (?.) or non-null asserted (!!.) calls are allowed on a nullable receiver of type B?
给A类的a函数加上 @Suppress("UNSAFE_CALL") 后idea不标红了,编译时会提示 Error:(16, 13) Kotlin: Reference has a nullable type 'B?', use explicit '?.invoke()' to make a function-like call instead

但是如果将B类改成下面这样子,将invoke从对象体里面移出来用扩展函数实现就不会在报错了:

class B 
operator fun B.invoke() {
    println("B invoke")
}

反编译后的java代码:

   public final void a() {
      if (this.b != null) {
         AaaKt.invoke(this.b);
         B var10000 = this.b;
         Intrinsics.checkExpressionValueIsNotNull(var10000, "b");
         AaaKt.invoke(var10000);
      }

   }

主要问题有三个个:
1、为什么将invoke方法改为扩展函数后并且输出正确结果而类方法却不行?
2、作为类方法时从idea自带的反编译工具生成的结果来看都b()和invoke()生成的字节码都是一样的且符合预期,为什么kotlin编译器却在编译时报错?
3、印象中Suppress应该能够抑制编译时的异常的,但是这里仍然报错了,是要有什么特殊条件才能抑制吗?


#2

1.扩展函数,本质是静态方法,你看一下生成的java代码就知道了
2.编译器报错,是提示你b可能为null,所以不能那么写,哪怕你加了if(b!=null)但依然爆错,给你段不会报错的代码,自己体会吧
val t=b?:return;
t.invoke()
t()
3.以上代码不加Suppress也可以正常运行


京ICP备16022265号-2 Kotlin China 2017 - 2018