Kotlin中的crossinline

One_Month發表於2020-10-09

這一篇看下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語句,等於明確指定了返回地方)

接下來再說到crossinline,我們再將上面的函式改一下

inline fun mainInline2(func1: () -> Unit) {
        runOnUiThread {
            func1()  //編譯器報錯
        }
    }

我們在行內函數中新增一個runOnUiThread,然後在他內部呼叫func1函式,編譯器報錯,會提醒func1可能包含這非當前返回的return,這樣又回到了之前的歧義問題,如果func1包含了return,那麼這個return返回的是runOnUiThread還是更外部的呼叫函式就有歧義,如果想這樣去間接呼叫,我們就需要加上crossinline

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。

小結:如果想允許間接呼叫函式型別引數,新增crossinline

相關文章