Kotlin标准函数run,with,let,also和apply的使用和区别

选择哪种函数

1.让我们看看源码中是如何定义的

/**
 * Calls the specified function [block] and returns its result.
 */
@kotlin.internal.InlineOnly
public inline fun <R> run(block: () -> R): R {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    return block()
}

/**
 * Calls the specified function [block] with `this` value as its receiver and returns its result.
 */
@kotlin.internal.InlineOnly
public inline fun <T, R> T.run(block: T.() -> R): R {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    return block()
}

/**
 * Calls the specified function [block] with the given [receiver] as its receiver and returns its result.
 */
@kotlin.internal.InlineOnly
public inline fun <T, R> with(receiver: T, block: T.() -> R): R {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    return receiver.block()
}

/**
 * Calls the specified function [block] with `this` value as its receiver and returns `this` value.
 */
@kotlin.internal.InlineOnly
public inline fun <T> T.apply(block: T.() -> Unit): T {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    block()
    return this
}

/**
 * Calls the specified function [block] with `this` value as its argument and returns `this` value.
 */
@kotlin.internal.InlineOnly
@SinceKotlin("1.1")
public inline fun <T> T.also(block: (T) -> Unit): T {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    block(this)
    return this
}

/**
 * Calls the specified function [block] with `this` value as its argument and returns its result.
 */
@kotlin.internal.InlineOnly
public inline fun <T, R> T.let(block: (T) -> R): R {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    return block(this)
}

看每个方法的返回值类型
apply,also返回的是它本身类型
run,with,let返回的是代码块最后一行的返回值类型

2.各个函数的应用场景

2.1 T.apply应用场景

//普通方法
fun createIntent(): Intent {
        val intent = Intent()
        intent.putExtra("nameFirst", "firstValue")
        intent.putExtra("nameSecond", "secondValue")
        return intent
}

//通过apply函数
fun createIntentByApply(): Intent =
            Intent().apply {
                putExtra("nameFirst", "firstValue")
                putExtra("nameSecond", "secondValue")
            }

//通过apply函数链式调用
fun createIntentByChainedApply(): Intent =
            Intent().apply { putExtra("nameFirst", "firstValue") }
                    .apply { putExtra("nameSecond", "secondValue") }

2.2 T.also函数

"abc".also {
    print("The String is $it") // "abc"
    it.reversed()
}.also {
    print("The reverse String is $it") // "abc"
    it.length
}.also {
    println("The length of the String is $it") // "abc"
}

2.3 T.let函数

"abc".let {
    println("The String is $it") // "abc"
    it.reversed() 
}.let {
    println("The reverse String is $it") // "cba"
    it.length  
}.let {
    println("The length of the String is $it") // 3
}

和also函数相比返回值不同,T.let返回的是作用域最后一个对象(可和自身对象不同),
T.also返回的都是原来自身对象。

两者结合使用场景
//原始函数
fun makeDir(path: String): File  {
    val result = File(path)
    result.mkdirs()
    return result
}

//通过let和also的链式调用改进后的函数
fun makeDir(path: String) = path.let{ File(it) }.also{ it.mkdirs() }

2.4 run函数使用场景

run {
    if (islogin) loginDialog else getAwardDialog
}.show()

2.5 with函数使用场景

with(webView.settings){
    javaScriptEnabled = true
    databaseEnabled = true
}

2.6 T.run函数使用场景

//此时run函数比上面例子要更好,因为在调用函数之前进行null检查
webView.settings?.run { 
    javaScriptEnabled = true
    databaseEnabled = true
}

参考文献

https://juejin.im/entry/5aaaa9156fb9a028dc40c1b2

猜你喜欢

转载自blog.csdn.net/mr_freeler/article/details/80938609
今日推荐