run、let、with、 apply 、also区别

1.run

run 是任何类型T的通用扩展函数,执行了返回类型为R的扩展函数block,最终返回该扩展函数的结果。


@kotlin.internal.InlineOnly
public inline fun <T, R> T.run(block: T.() -> R): R {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    return block()
}

1.对象配置并且计算结果

 val result = service.run {
    port = 8080
    query(prepareRequest() + " to port $port")
}

2.在需要表达式的地方运行语句:非扩展的run

除了在接收者对象上调用 run 之外,还可以将其用作非扩展函数。 非扩展 run 可以使你在需要表达式的地方执行一个由多个语句组成的块。

fun main() {
//此处run返回一个对象,且初始化对象并返回
    val hexNumberRegex = run {
        val digits = "0-9"
        val hexDigits = "A-Fa-f"
        val sign = "+-"

        Regex("[$sign]?[$digits$hexDigits]+")
    }

    for (match in hexNumberRegex.findAll("+1234 -FFFF not-a-number")) {
        println(match.value)
    }
}

2.let

let 可用于在调用链的结果上调用一个或多个函数,或者说基于代码的结果再执行相关逻辑


@kotlin.internal.InlineOnly
public inline fun <T, R> T.let(block: (T) -> R): R {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    return block(this)
}
tabList?.let { it: ArrayList<Tab> ->
    createWebView(tabList)
}
//tabList不为null,就执行逻辑        

it参数:表示主体对象,可以基于当前对象做下一步操作。it也可以修改为其他标识

let 经常用于仅使用非空值执行代码块,返回的也是高阶函数的结果

3. run let 区别:

相同点:都返回一个lambda表达式 run方法的高阶函数为block: T.() -> R let方法的高阶函数为block: (T) -> R,T作为参数传入,所以it代码T对象,也就是A对象。 不同点: run 高阶内部的无参数
let 高阶内部有参数,且为主体自身对象

例子:

class A {
    val x = 11
    fun test1(): String {
        return "this is A.test1()"
    }
    fun test2() {}
}

fun testRun() {
    val len = A().run { //此处有个无形的this 
        test1()
    }.length
    println("A的run 方法返回字符串长度为$len")
}

fun testLet() {
    val result = A().let { it ->
        it.test1()
    }.length
    println("A的let 方法返回字符串为$result")
}

fun main() {
    testRun()
    testLet()
}

通过代码可以看到A对象,run方法的作用域就是A对象,可以直接调用test1()方法, 但是let不同,是通过it关键字才能执行test1()方法,这是最大的不同,也是唯一的不同的地方。

4.with

@kotlin.internal.InlineOnly
public inline fun <T, R> with(receiver: T, block: T.() -> R): R {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    return receiver.block()
}

查看源码,个人认为with和run 区别不大, 1.with需要一个接收者 2.尾部的高阶函数的作用域就是接收者的作用域,也是this表示。返回的结果是高阶函数的结果。

例子:

fun testWith() {
    with(A()) {
        this.test1()
    }
}

5.apply

apply也类似于run,高阶函数的作用域为当前接收者对象作用域,高阶函数无返回值,但是方法为返回值,为接收者对象。

public inline fun <T> T.apply(block: T.() -> Unit): T {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    block()
    return this
}

主要应用于对象的配置,返回对象自身

val adam = Person("Adam").apply { //this ->
    age = 32
    city = "London"
}
println(adam)

6.also

参数为it,返回自身对象
also 类似于let,但是注意高阶函数的返回值为自身T对象


public inline fun <T> T.also(block: (T) -> Unit): T {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    block(this)
    return this
}
val numbers = mutableListOf("one", "two", "three")
numbers.also {
    println("The list elements before adding new one: $it")
}.add("four")

案列:

fun testAlso() {
    A().also { it ->
        it.x == 44
    }.test1()
}

it代码A对象,高阶函数的返回值还是A对象,所以后缀还可以调用test1()

7.takeIf 、takeUnless

takeIf 可以即判断,还可以加入条件。

public inline fun <T> T.takeIf(predicate: (T) -> Boolean): T? {
    contract {
        callsInPlace(predicate, InvocationKind.EXACTLY_ONCE)
    }
    return if (predicate(this)) this else null
}

只操作单条数据,相反的有takeUnless函数

val result = Student.takeif { it.age > 18 }.let { ... }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值