詳解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)行抉擇,我無恥的盜用一張很有用的圖(貌似地址需要翻墻),相信能幫到你:
圖片來自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