一、內(nèi)聯(lián)拓展函數(shù) let
let 擴(kuò)展函數(shù)的實(shí)際上是一個(gè)作用域函數(shù),當(dāng)你需要去定義一個(gè)變量在一個(gè)特定的作用域范圍內(nèi),let函數(shù)的是一個(gè)不錯(cuò)的選擇;let函數(shù)另一個(gè)作用就是可以避免寫一些判斷null的操作。
1.1 let 函數(shù)的使用的一般結(jié)構(gòu)
object.let {
it.todo() //在函數(shù)體內(nèi)使用it替代object對象去訪問其公有的屬性和方法
...
}
//另一種用途 判斷object為null的操作
object?.let { //表示object不為null的條件下,才會(huì)去執(zhí)行l(wèi)et函數(shù)體
it.todo()
}
1.2 let函數(shù)底層的inline擴(kuò)展函數(shù)+lambda結(jié)構(gòu)
@kotlin.internal.InlineOnly
public inline fun <T, R> T.let(block: (T) -> R): R {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
return block(this)
}
意思就是 T 類型的對象調(diào)用 let 方法,實(shí)際調(diào)用的是傳入 let 方法的 lambda 表達(dá)式的 block 塊,最終返回 lambda 表達(dá)式的返回值。
lambda 表達(dá)式內(nèi)部通過 it 指代該對象。
1.3 let 函數(shù)常見的適用的場景
場景一: 最常用的場景就是使用let函數(shù)處理需要針對一個(gè)可null的對象統(tǒng)一做判空處理。
場景二: 然后就是需要去明確一個(gè)變量所處特定的作用域范圍內(nèi)可以使用
obj?.funA()
obj?.funB()
obj?.funC()
obj?.let {
it.funA()
it.funB()
it.funC()
}
二、內(nèi)聯(lián)函數(shù) with
2.1 with 函數(shù)使用的一般結(jié)構(gòu)
with(object) {
//todo
}
2.2 with 函數(shù)底層的inline擴(kuò)展函數(shù)+lambda 結(jié)構(gòu)
@kotlin.internal.InlineOnly
public inline fun <T, R> with(receiver: T, block: T.() -> R): R {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
return receiver.block()
}
注意,這個(gè) with 函數(shù)不是拓展函數(shù),它接收兩個(gè)參數(shù),第一個(gè)參數(shù)是要是用的對象,第二個(gè)參數(shù)是一個(gè) lambda 表達(dá)式,該方法實(shí)際調(diào)用的是第一個(gè)參數(shù)對象,進(jìn)行 block 塊的調(diào)用,
最終返回 lambda 表達(dá)式的返回值。
lambda 表達(dá)式內(nèi)部通過 this 指代該對象。
2.3 with 函數(shù)的適用的場景
適用于調(diào)用同一個(gè)類的多個(gè)方法時(shí),可以省去類名重復(fù),直接調(diào)用類的方法即可,經(jīng)常用于Android中RecyclerView中onBinderViewHolder中,數(shù)據(jù)model的屬性映射到UI上。
obj.funA()
obj.funB()
obj.funC()
with(obj) {
this.funA()
funB() // this 可省略
funC)
}
三、 內(nèi)聯(lián)拓展函數(shù) run
3.1 run 函數(shù)使用的一般結(jié)構(gòu)
object.run {
// todo
}
3.2 run 函數(shù)的inline+lambda 結(jié)構(gòu)
@kotlin.internal.InlineOnly
public inline fun <T, R> T.run(block: T.() -> R): R {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
return block()
}
run 函數(shù)實(shí)際上可以說是let和with兩個(gè)函數(shù)的結(jié)合體,run函數(shù)只接收一個(gè)lambda函數(shù)為參數(shù),以閉包形式返回,即返回 lambda 表達(dá)式的返回值。
3.3 run 函數(shù)的適用場景
obj?.funA()
obj?.funB()
obj?.funC()
obj?.run {
this.funA()
funB() // this 可省略
funC)
}
四、內(nèi)聯(lián)拓展函數(shù) apply
4.1 apply 函數(shù)使用的一般結(jié)構(gòu)
object.apply {
// todo
}
4.2 apply 函數(shù)的inline+lambda結(jié)構(gòu)
@kotlin.internal.InlineOnly
public inline fun <T> T.apply(block: T.() -> Unit): T {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
block()
returnthis
}
從結(jié)構(gòu)上來看apply函數(shù)和run函數(shù)很像,唯一不同點(diǎn)就是它們各自返回的值不一樣,run函數(shù)是以閉包形式返回最后一行代碼的值,而apply函數(shù)的返回的是傳入對象的本身。
五、內(nèi)聯(lián)擴(kuò)展函數(shù) also
5.1 also 函數(shù)使用的一般結(jié)構(gòu)
object.also {
// todo
}
5.2 also 函數(shù)的inline+lambda結(jié)構(gòu)
public inline fun <T> T.also(block: (T) -> Unit): T {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
block(this)
returnthis
}
also函數(shù)的結(jié)構(gòu)實(shí)際上和let很像唯一的區(qū)別就是返回值的不一樣,let是以閉包的形式返回,返回函數(shù)體內(nèi)最后一行的值,如果最后一行為空就返回一個(gè)Unit類型的默認(rèn)值。而also函數(shù)返回的則是傳入對象的本身。
六、比較總結(jié)
函數(shù)名 |
定義inline的結(jié)構(gòu) |
函數(shù)體內(nèi)使用的對象 |
返回值 |
是否是擴(kuò)展函數(shù) |
let |
fun T.let(block: (T) -> R): R = block(this) |
it指代當(dāng)前對象 |
閉包形式返回 |
是 |
with |
fun with(receiver: T, block: T.() -> R): R = receiver.block() |
this指代當(dāng)前對象或者省略 |
閉包形式返回 |
否 |
run |
fun T.run(block: T.() -> R): R = block() |
this指代當(dāng)前對象或者省略 |
閉包形式返回 |
是 |
apply |
fun T.apply(block: T.() -> Unit): T |
this指代當(dāng)前對象或者省略 |
返回this |
是 |
also |
fun T.also(block: (T) -> Unit): T |
it指代當(dāng)前對象 |
返回this |
是 |
七、實(shí)用例子————Kotlin 實(shí)現(xiàn)單例模式
Kotlin 實(shí)現(xiàn)單例模式相對 java 來說很簡單。比如通過 object, by lazy 操作,相信大家都會(huì)。但有時(shí)候,我們想要在單例初始化的時(shí)候順便做一下其它初始化,極有可能會(huì)還需要傳入?yún)?shù)。
使用 java 時(shí),我最喜歡的實(shí)現(xiàn)單例模式是靜態(tài)內(nèi)部類的方式,但在 Android 中經(jīng)常在初始化的時(shí)候需要傳入 context ,然后選擇了雙重檢查鎖方式。
先看 java 代碼:
public class Singleton {
private Singleton() {
}
/**
* volatile is since JDK5
*/
private static volatile Singleton sSingleton;
public static Singleton getInstance() {
if (sSingleton == null) {
synchronized (Singleton.class) {
// 未初始化,則初始instance變量
if (sSingleton == null) {
sSingleton = new Singleton();
}
}
}
return sSingleton;
}
}
再看看我們用 kotlin 實(shí)現(xiàn)文章來源:http://www.zghlxwxcb.cn/news/detail-792869.html
class Singleton private constructor(){
companion object {
@Volatile
private var instance: Singleton? = null
fun getInstance(context: Context): Singleton {
return instance?: synchronized(this) {
instance?:Singleton().also {
instance = it
}
}
}
}
}
如果要做初始化操作,我們完全可以在 also 函數(shù)里面去處理。文章來源地址http://www.zghlxwxcb.cn/news/detail-792869.html
到了這里,關(guān)于Kotlin 之 let、with、run、apply、also 函數(shù)的使用的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!