詳解Kotlin操作符:T.apply、T.let、T.run、T.also、with、run

詳解Kotlin操作符:T.apply、T.let、T.run、T.also、with、run

乍看這6個操作符,挺唬人的,又要花費不少腦細(xì)胞去理解和區(qū)分,沒辦法,只能這樣。希望看完這片這篇文章能幫到你。

First things first,來研究下run和with這兩個操作符,為啥先他倆呢?難道你沒發(fā)現(xiàn)就他倆調(diào)用不需要變量,而其余四個則需要一個變量T才能調(diào)用?

with
先看看標(biāo)準(zhǔn)庫里的源碼:

public inline fun with(receiver: T, block: T.() -> R) : R = receiver.block()

一眼就能明白,with就是一個內(nèi)斂函數(shù)且接收兩個參數(shù),talk is cheap:

classJujube{
  fun violet(){
    val str="Jujube"
    val result=with(str,{
      println(this)// 接收者
//            println(it) // 參數(shù) with操作符不能識別it
      68//區(qū)間返回值
    })
    println(result)
  }
}

fun main(vararg args:String){
  Jujube().violet()
}

先說明:上面的代碼不規(guī)范。由于with的第二個參數(shù)是最后一個參數(shù)而且類型是lambda,那么可以挪到小括號外面(稱之為裸奔的lambda),那么上面的代碼規(guī)范的寫法就是如下:

classJujube{
  fun violet(){
    val str="awegerg"
    val result=with(str){
      println(this)// 接收者
//            println(it) // 參數(shù) with操作符不能識別it
      68//區(qū)間返回值
    }
    println(result)
  }
}

fun main(vararg args:String){
  Jujube().violet()
}

打印結(jié)果是
awegerg
68
就這么多,wiht操作符是不是很簡單?

run
先看看標(biāo)準(zhǔn)庫里的源碼:

public inline fun T.run(block:T.()->R):R=block() 

run同樣是一個內(nèi)斂函數(shù),但是相對于with來說,run只接收一個lambda參數(shù),這是第一點區(qū)別。因此套用之前的代碼的話,會出現(xiàn)下面的代碼:

classJujube{
  fun violet(){
    val str="awegerg"
    val result=run{
      println(this)// 接收者
//            println(it) //
      68//區(qū)間返回值
  }
  println(result)
}

}

fun main(vararg args:String){
  Jujube().violet()
}

打印結(jié)果是
com.htgames.nutspoker.debug.fo.Jujube@1540e19d
68

根據(jù)打印結(jié)果你能看出run和with的第二點區(qū)別了嗎?相信你應(yīng)該能,就是他倆的this指向的引用不同,with中的this指向的是它的第一個參數(shù),而run中的this指向的是對象實例。with和run大概就這兩點區(qū)別吧。

T.let
源碼:

publicinlinefunT.let(block:(T)->R):R=block(this)

接收一個lambda參數(shù)而已。

classJujube{
  fun violet(){
    val str="awegerg"
    val result=str.let{
      println(this)// 接收者
      println(it)
      68//區(qū)間返回值
    }
    println(result)
  }
}

fun main(vararg args:String){
  Jujube().violet()
}

打印結(jié)果是
com.htgames.nutspoker.debug.fo.Jujube@1540e19d
awegerg
68

把打印結(jié)果用表格顯示更清晰:


使用T.run、T.apply、T.also套用上面的代碼,用表格顯示它們的打印結(jié)果如下:


結(jié)合之前介紹的with和run,那么最終的表格如下:


Second things second,我在項目開發(fā)中用的比較多的是with和T.apply,用的多了就明白它們的區(qū)別了。但是到底如何對這6個操作符進(jìn)行抉擇,我無恥的盜用一張很有用的圖(貌似地址需要翻墻),相信能幫到你:
image

圖片來自https://android.jlelse.eu/mastering-kotlin-standard-functions-run-with-let-also-and-apply-9cd334b0ef84

Third things third, 小技巧:使用T.let和T.apply可以對一個變量進(jìn)行集體操作,如果需要對變量進(jìn)行非空檢查,那么直接在T后面加上?符號即可,避免了Java中泛濫的if-else的非空語句判斷,stop shitting,show you the code below:

vartextView:TextView?=TextView(this)
  textView?.apply{//對textView進(jìn)行集體操作
  this.text="a"
  this.isClickable=true
  this.setOnClickListener{Toast.makeText(this@MainActivity,"click",Toast.LENGTH_SHORT).show()}
}

Last things last, 小技巧:使用run操作符可以對語句添加標(biāo)簽。不知道你在開發(fā)中是否遇到這種情景:想要在forEach語句中使用break或者continue。那么問題來了,android studio編輯器會報“break or continue jumps across a function or a class boundary”,這時候run就可以大顯神通了,代碼如下:

fun main(vararg args:String){
  var sameItems = ArrayList()
  run run@{//添加標(biāo)簽
    for(i in0until6){
      varhasSame=false
      run outer@{//添加標(biāo)簽
        (4..6).forEach dangerous@{
          if(it==i){
            hasSame=true
            sameItems.add(it)
            return@outer//返回到outer標(biāo)簽,效果相當(dāng)于break
          }
        }
      }
      //do something
    }
  }
}

有任何疑問請聯(lián)系:
owl@violetpersimmon.com

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容