<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      kotlin函數和Lambda表達式——>內聯函數

      1.內聯函數

        使用高階函數會帶來一些運行時的效率損失:每一個函數都是一個對象,并且會捕獲一個閉包。即那些 在函數體內會訪問到的變量。內存分配(對于函數對象和類)和虛擬調用會引入運行時間開銷。

        但是在許多情況下通過內聯化 lambda 表達式可以消除這類的開銷。下述函數是這種情況的很好的例 子。即 lock() 函數可以很容易地在調用處內聯。考慮下面的情況

      lock(l) { foo() }

        編譯器沒有為參數創建一個函數對象并生成一個調用。取而代之,編譯器可以生成以下代碼:

          l.lock() 
          try {
              foo()
          } finally {
              l.unlock()
          }

        為了讓編譯器這么做,我們需要使用 inline 修飾符標記 lock() 函數:

      inline fun <T> lock(lock: Lock, body: () -> T): T { ...... }

        inline 修飾符影響函數本身和傳給它的 lambda 表達式:所有這些都將內聯到調用處。

        內聯可能導致生成的代碼增加;不過如果我們使用得當(即避免內聯過大函數),性能上會有所提升,尤 其是在循環中的“超多態(megamorphic)”調用處。

      2.禁用內聯

        如果希望只內聯一部分傳給內聯函數的 lambda 表達式參數,那么可以用 noinline 修飾符標記不希望內聯的函數參數

      inline fun foo(inlined: () -> Unit, noinline notInlined: () -> Unit) { ...... }

        可以內聯的 lambda 表達式只能在內聯函數內部調用或者作為可內聯的參數傳遞,但是 noinline的可以以任何我們喜歡的方式操作:存儲在字段中、傳送它等等。

        需要注意的是,如果一個內聯函數沒有可內聯的函數參數并且沒有具體化的類型參數,編譯器會產生一 個警告,因為內聯這樣的函數很可能并無益處(如果你確認需要內聯,則可以用@Suppress("NOTHING_TO_INLINE") 注解關掉該警告)。

      非局部返回

        在 Kotlin 中,我們只能對具名或匿名函數使用正常的、非限定的 return 來退出。這意味著要退出一個 lambda表達式,我們必須使用一個標簽,并且在lambda表達式內部禁止使用裸 return,因為lambda 表達式不能使包含它的函數返回:

      fun foo() { 
          ordinaryFunction {
              return // 錯誤:不能使 `foo` 在此處返回 
          }
      }

        但是如果 lambda 表達式傳給的函數是內聯的,該 return 也可以內聯,所以它是允許的: inline fun inlined(block: () -> Unit) { println("hi!") }

      fun foo() {
              inlined {
                   return // OK:該 lambda 表達式是內聯的
              }
          }
      }

        這種返回(位于 lambda 表達式中,但退出包含它的函數)稱為非局部返回。我們習慣了在循環中用這種結構,其內聯函數通常包含

      fun hasZeros(ints: List<Int>): Boolean {
           ints.forEach {
               if (it == 0) return true // 從 hasZeros 返回 
           }
           return false
      }

        請注意,一些內聯函數可能調用傳給它們的不是直接來自函數體、而是來自另一個執行上下文的 lambda 表達式參數,例如來自局部對象或嵌套函數。在這種情況下,該 lambda 表達式中也不允許非局 部控制流。為了標識這種情況,該 lambda 表達式參數需要用 crossinline 修飾符標記:

       inline fun f(crossinline body: () -> Unit) {
              val f = object : Runnable {
                  override fun run() = body()
              }
              // ......
      }

        break和continue在內聯的 lambda 表達式中還不可用,但我們也計劃支持它們。

      3.具體化的類型參數

        有時候我們需要訪問一個作為參數傳給我們的一個類型:

      fun <T> TreeNode.findParentOfType(clazz: Class<T>): T? {
          var p = parent
          while (p != null && !clazz.isInstance(p)) {
              p = p.parent
          }
          @Suppress("UNCHECKED_CAST")
          return p as T?
      }

        在這里我們向上遍歷一棵樹并且檢測每個節點是不是特定的類型。這都沒有問題,但是調用處不是很優雅:

      treeNode.findParentOfType(MyTreeNode::class.java)

        我們真正想要的只是傳一個類型給該函數,即像這樣調用它

      treeNode.findParentOfType<MyTreeNode>()

        為能夠這么做,內聯函數支持具體化的類型參數,于是我們可以這樣寫

      inline fun <reified T> TreeNode.findParentOfType(): T? {
          var p = parent
          while (p != null && p !is T) {
              p = p.parent
          }
          return p as T?
      }

        我們使用 reified 修飾符來限定類型參數,現在可以在函數內部訪問它了,幾乎就像是一個普通的類 一樣。由于函數是內聯的,不需要反射,正常的操作符如 !is 和 as 現在都能用了。此外,我們還可以按 照上面提到的方式調用它:myTree.findParentOfType<MyTreeNodeType>() 。

        雖然在許多情況下可能不需要反射,但我們仍然可以對一個具體化的類型參數使用它:

      inline fun <reified T> membersOf() = T::class.members
      fun main(s: Array<String>) {
          println(membersOf<StringBuilder>().joinToString("\n"))
      }

        普通的函數(未標記為內聯函數的)不能有具體化參數。不具有運行時表示的類型(例如非具體化的類型 參數或者類似于 Nothing 的虛構類型)不能用作具體化的類型參數的實參。

      4.內聯屬性(自1.1起)

        inline 修飾符可用于沒有幕后字段的屬性的訪問器。你可以標注獨立的屬性訪問器:

      val foo: Foo
          inline get() = Foo()
      var bar: Bar 
          get() = ......
          inline set(v) { ...... }

        你也可以標注整個屬性,將它的兩個訪問器都標記為內聯

      inline var bar: Bar 
          get() = ......
          set(v) { ...... }

        在調用處,內聯訪問器如同內聯函數一樣內聯

      5.公有API內聯函數的限制

        當一個內聯函數是 public 或 protected 而不是 private 或 internal 聲明的一部分時,就會 認為它是一個模塊級的公有 API。可以在其他模塊中調用它,并且也可以在調用處內聯這樣的調用。

        這帶來了一些由模塊做這樣變更時導致的二進制兼容的?險?聲明一個內聯函數但調用它的模塊在 它修改后并沒有重新編譯。

        為了消除這種由非公有 API 變更引入的不兼容的?險,公有 API 內聯函數體內不允許使用非公有聲明, 即,不允許使用 private 與 internal 聲明以及其部件。

        一個 internal 聲明可以由 @PublishedApi 標注,這會允許它在公有 API 內聯函數中使用。當一 個 internal 內聯函數標記有 @PublishedApi 時,也會像公有函數一樣檢測其函數體。

       

      posted @ 2020-07-01 15:15  王世楨  閱讀(407)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 精品人妻伦一二三区久久aaa片| 在线亚洲午夜理论av大片| 欧美日韩在线视频| 亚洲国产区男人本色vr| 精品亚洲男人一区二区三区| 强d乱码中文字幕熟女1000部| 成人精品视频一区二区三区| 成人av天堂网在线观看| 国产成人亚洲综合色婷婷秒播| 久久一区二区中文字幕| 亚洲高清国产拍精品熟女| 久久精品伊人狠狠大香网| a级黑人大硬长爽猛出猛进| 精品人妻午夜福利一区二区| 亚洲成人av免费一区| 国产白丝无码免费视频| 国产精品亚洲专区无码导航| 亚洲制服无码一区二区三区| 双峰县| 四虎成人高清永久免费看| 国产精品大片中文字幕| 国产精品理论片| 亚洲av综合av一区| 国产精品点击进入在线影院高清 | 女的被弄到高潮娇喘喷水视频| 宝贝腿开大点我添添公视频免| 无码人妻精品丰满熟妇区| 亲子乱aⅴ一区二区三区| 亚洲性色AV一区二区三区| 国产午夜福利在线视频| 亚洲欧美日韩人成在线播放| 日本丰满少妇高潮呻吟| 在线观看无码av免费不卡网站| 一本久道久久综合久久鬼色| 熟女人妻aⅴ一区二区三区电影| 免费无码va一区二区三区| 亚洲 一区二区 在线| 永久天堂网 av手机版| 日本道播放一区二区三区| 亚洲天堂在线免费| 国产明星精品无码AV换脸 |