<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Kotlin修煉指南(一)

          共 5937字,需瀏覽 12分鐘

           ·

          2020-08-16 04:33

          最近會(huì)寫一些關(guān)于kotlin的文章,主要是為了引出函數(shù)式編程的概念,并介紹kotlin中的一些騷操作。第一篇文章主要介紹作用域函數(shù)。

          作用域函數(shù)

          作用域函數(shù)是Kotlin中的一個(gè)非常有用的函數(shù),它主要分為兩種,一種是拓展函數(shù)式,另一種是頂層函數(shù)式。作用域函數(shù)的主要功能是為調(diào)用函數(shù)提供一個(gè)內(nèi)部范圍,同時(shí)結(jié)合kotlin的語法糖提供一些便捷操作。

          作用域函數(shù)主要有下面這幾種,它們的主要區(qū)別就是函數(shù)體內(nèi)使用對象和返回值的區(qū)別。

          • run

          函數(shù)體內(nèi)使用this代替本對象。返回值為函數(shù)最后一行或者return指定的表達(dá)式

          • let

          函數(shù)內(nèi)使用it代替本對象。返回值為函數(shù)最后一行或者return指定的表達(dá)式。

          • apply

          函數(shù)內(nèi)使用this代替本對象。返回值為本對象。

          • also

          函數(shù)內(nèi)使用it代替本對象。返回值為本對象。

          • takeIf

          條件為真返回對象本身否則返回null。

          • takeUnless

          條件為真返回null否則返回對象本身。

          • with

          with比較特殊,不是以擴(kuò)展方法的形式存在的,而是一個(gè)頂級函數(shù)。
          傳入?yún)?shù)為對象,函數(shù)內(nèi)使用this代替對象。
          返回值為函數(shù)最后一行或者return指定的表達(dá)式。

          • repeat

          將函數(shù)體執(zhí)行多次。

          通過表格進(jìn)行下總結(jié),如下所示。

          操作符this/it返回值
          letit最后一行或者return指定的表達(dá)式
          withit最后一行或者return指定的表達(dá)式
          runthis最后一行或者return指定的表達(dá)式
          alsothis上下文對象
          applythis上下文對象

          下面通過一個(gè)簡單的例子來演示下這些作用域函數(shù)的基本使用方式。

          class TestBean {
          var name: String = "xuyisheng"
          var age: Int = 18
          }
          fun main(args: Array) {
          val test = TestBean()
          val resultRun = test.run {
          name = "xys"
          age = 3
          println("Run內(nèi)部 $this")
          age
          }
          println("run返回值 $resultRun")
          val resultLet = test.let {
          it.name = "xys"
          it.age = 3
          println("let內(nèi)部 $it")
          it.age
          }
          println("let返回值 $resultLet")
          val resultApply = test.apply {
          name = "xys"
          age = 3
          println("apply內(nèi)部 $this")
          age
          }
          println("apply返回值 $resultApply")
          val resultAlso = test.also {
          it.name = "xys"
          it.age = 3
          println("also內(nèi)部 $it")
          it.age
          }
          println("also返回值 $resultAlso")
          val resultWith = with(test) {
          name = "xys"
          age = 3
          println("with內(nèi)部 $this")
          age
          }
          println("with返回值 $resultWith")
          test.age = 33
          val resultTakeIf = test.takeIf {
          it.age > 3
          }
          println("takeIf $resultTakeIf")
          val resultTakeUnless = test.takeUnless {
          it.age > 3
          }
          println("takeUnless $resultTakeUnless")
          }

          執(zhí)行結(jié)果如下所示。

          Run內(nèi)部 TestBean@27c170f0
          run返回值 3
          let內(nèi)部 TestBean@27c170f0
          let返回值 3
          apply內(nèi)部 TestBean@27c170f0
          apply返回值 TestBean@27c170f0
          also內(nèi)部 TestBean@27c170f0
          also返回值 TestBean@27c170f0
          with內(nèi)部 TestBean@27c170f0
          with返回值 3
          takeIf TestBean@27c170f0
          takeUnless null

          官網(wǎng)上提供了一張圖來整理這些作用域函數(shù)的使用場景,如下所示。

          頂級函數(shù)使用場景

          run、with、repeat,是比較常用的3個(gè)頂級函數(shù),它們是區(qū)別于其它幾種拓展函數(shù)類型的,它們的使用也比較簡單,示例代碼如下所示。

          • run

          fun testRun() {
          var str = "I am xys"
          run {
          val str = "I am zj"
          println(str) // I am xys
          }
          println(str) // I am zj
          }

          可以發(fā)現(xiàn),run頂級函數(shù)提供了一個(gè)獨(dú)立的作用域,可以在該作用域內(nèi)完整的使用全新的變量和屬性。

          • repeat

          repeat(5){
          print("repeat")
          }

          repeat比較簡單,直接將函數(shù)體按指定次數(shù)執(zhí)行。

          • with

          前面的代碼已經(jīng)演示過with如何使用。

          with(ArrayList()) {
          add("a")
          add("b")
          add("c")
          println("this = " + this)
          this
          }

          要注意的是其返回值是根據(jù)return的類型或者最后一行代碼來進(jìn)行判斷的。

          拓展函數(shù)使用場景

          ?.結(jié)合拓展函數(shù)

          Kotlin的?操作符和作用域函數(shù)的拓展函數(shù)可以非常方便的進(jìn)行對象的判空及后續(xù)處理,例如下面的例子。

          // 對result進(jìn)行了判空并bindData
          result?.let {
          if (it.isNotEmpty()) {
          bindData(it)
          }
          }

          簡化對象的創(chuàng)建

          類似apply這樣的作用域函數(shù),可以返回this的作用域函數(shù),可以將對象的創(chuàng)建和屬性的賦值寫在一起,簡化代碼,類似builder模式,例如下面的這個(gè)例子。

          // 使用普通的方法創(chuàng)建一個(gè)Fragment
          fun createInstance(args: Bundle) : MyFragment {
          val fragment = MyFragment()
          fragment.arguments = args
          return fragment
          }
          // 通過apply來創(chuàng)建一個(gè)Fragment
          fun createInstance(args: Bundle)
          = MyFragment().apply { arguments = args }

          再例如下面的實(shí)現(xiàn)。

          // 使用普通的方法創(chuàng)建Intent
          fun createIntent(intentData: String, intentAction: String): Intent {
          val intent = Intent()
          intent.action = intentAction
          intent.data = Uri.parse(intentData)
          return intent
          }

          // 通過apply函數(shù)的鏈?zhǔn)秸{(diào)用創(chuàng)建Intent
          fun createIntent(intentData: String, intentAction: String) =
          Intent().apply { action = intentAction }
          .apply { data = Uri.parse(intentData) }

          以及下面的實(shí)現(xiàn)。

          // 正常方法
          fun makeDir(path: String): File {
          val result = File(path)
          result.mkdirs()
          return result
          }
          // 改進(jìn)方法
          fun makeDir(path: String)
          = path.let{ File(it) }.also{ it.mkdirs() }

          同一對象的多次操作

          在開發(fā)中,有些對象有很多參數(shù)或者方法需要設(shè)置,但該對象又沒用提供builder方式進(jìn)行構(gòu)建,例如下面的例子。

          val linearLayout = LinearLayout(itemView.context).apply {
          orientation = LinearLayout.VERTICAL
          layoutParams = LinearLayout.LayoutParams(
          LinearLayout.LayoutParams.MATCH_PARENT,
          LinearLayout.LayoutParams.WRAP_CONTENT)
          }

          progressBar.apply {
          progress = newProgress
          visibility = if (newProgress in 1..99) View.VISIBLE else View.GONE
          }

          不論是let、run、apply還是其它拓展函數(shù),都可以實(shí)現(xiàn)這樣的需求,借助it或this,可以很方便的對該對象的多個(gè)屬性進(jìn)行操作。

          不過這些拓展函數(shù)還是有一些細(xì)微的差別的,例如T.run和T.let(即使用it和this的區(qū)別)

          • 使用it的作用域函數(shù),可以使用特定的變量名來重命名it,從而表達(dá)更清楚的語義。

          • this在大部分情況下是可以省略的,比使用it簡單

          例如下面的例子。

          stringResult?.let {
          nonNullString ->
          println("The non null string is $nonNullString")
          }

          通過對it的重命名,語義表達(dá)更加清楚。

          條件操作

          借助kotlin的?操作符,可以簡化很多條件操作,例如下面的幾個(gè)例子。

          url = intent.getStringExtra(EXTRA_URL)?.takeIf { it.isNotEmpty() } ?: run {
          toast("url空")
          activity.finish()
          }

          上面的代碼演示了【從intent中取出url并在url為空時(shí)的操作】。

          test.takeIf { it.name.isNotEmpty() }?.also { print("name is $it.name") } ?: print("name empty")

          上面代碼演示了【從test中取出name,不為空的時(shí)候和為空的時(shí)候的操作】。

          鏈?zhǔn)秸{(diào)用

          作用域函數(shù)的一個(gè)非常方便的作用就是通過其返回值的改變來組裝鏈?zhǔn)秸{(diào)用。一個(gè)簡單示例如下所示。

          test.also {
          // todo something
          }.apply {
          // todo something
          }.name = "xys"

          通過let來改變返回值,從而將不同的處理通過鏈?zhǔn)秸{(diào)用串聯(lián)起來。

          val original = "abc"
          // 改變值并且傳遞到下一鏈條
          original.let {
          println("The original String is $it") // "abc"
          it.reversed() // 改變參數(shù)并且傳遞到下一鏈條
          }.let {
          println("The reverse String is $it") // "cba"
          it.length // 改變參數(shù)類型并且傳遞到下一鏈條
          }.let {
          println("The length of the String is $it") // 3
          }

          上面的代碼借助let,可以將函數(shù)的返回值不斷進(jìn)行修改,從而直接將下一個(gè)操作進(jìn)行鏈?zhǔn)竭B接。
          而使用also(即返回this的作用域函數(shù))可以將多個(gè)對同一對象的操作進(jìn)行鏈?zhǔn)秸{(diào)用,如下所示。

          original.also {
          println("The original String is $it") // "abc"
          it.reversed() // 即使我們改變它,也是沒用的
          }.also {
          println("The reverse String is ${it}") // "abc"
          it.length // 即使我們改變它,也是沒用的
          }.also {
          println("The length of the String is ${it}") // "abc"
          }

          這里只是為了演示,所以將可以寫在同一個(gè)作用域函數(shù)中的進(jìn)行了拆分。

          also和let的鏈?zhǔn)秸{(diào)用,實(shí)際上各有不同的使用技巧,通過let,可以改變返回值,而通過also,可以將多個(gè)不同的原子操作通過鏈?zhǔn)竭M(jìn)行組合,讓邏輯更加明朗。

          國際慣例

          also & apply

          雖然also和apply都是返回this,但國際慣例,它們在使用的時(shí)候,還是有一些細(xì)微的差別的,also強(qiáng)調(diào)的是【與調(diào)用者無關(guān)的操作】,而apply強(qiáng)調(diào)的是【調(diào)用者的相關(guān)操作】,例如下面的這個(gè)例子。

          test?.also {
          println("some log")
          }?.apply {
          name = "xys"
          }

          let & run

          let和run的返回值相同,它們的區(qū)別主要在于作用域內(nèi)使用it和this的區(qū)別。一般來說,如果調(diào)用者的屬性和類中的屬性同名,則一般會(huì)使用let,避免出現(xiàn)同名的賦值引起混亂。

          國際慣例,run通常使用在鏈?zhǔn)秸{(diào)用中,進(jìn)行數(shù)據(jù)處理、類型轉(zhuǎn)換,例如?.run{}的使用。

          瀏覽 38
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  夜夜骑天天撸 | 亚洲成人短视频 | 一级a做视频在线免费观看 | 亚洲情热| 欧美日韩乱国产 |