Kotlin学习笔记(六)作用域函数run,with, apply,also,let,takeIf,takeUnless,repeat

作用域函数,就是些技巧性方法,函数定义全在Standard.kt文件里。本篇,用实例记录一下它们的用法。

1.所谓作用域函数:它们的lamda函数作用域===对象类内部作用域。 就像是对象类的内部方法一样。

这样在lamda函数内,可以直接调用对象的方法,属性,不需要通过对象实例点出方法,属性。

2. let/takeIf/takeLess, 需要it引导

3. with是独立函数,其他函数都可由对象点出来。

  • run,利用操作对象的方法属性,完成一些工作。最后在函数体内返回指定值。
        val list = listOf("apple", "orange", "pear")
        val result = StringBuilder().run {
            append("Start eating fruits.\n")
            for (fruit in list){
                append(fruit).append("\n")
            }

            append("Ate all fruits.")

            toString()
        }

        println(result)

  • apply,用于修改对象自己。修改后,如果函数有接收返回,接收的也是修改后的自己。函数体类不需要返回对象。
fun main() {
    val user = User("alan", 18)
    val applyResult = user.apply {
        //这儿都是user对象的作用域
        age = 20
    }
    println(applyResult) //输出:User(name=Peter, age=20)
    println(user) //输出:User(name=Peter, age=20)
    println(applyResult === user) //输出:true
}

data class User(var name: String, var age: Int)

第二个例子:

        val list = listOf("apple", "orange", "pear")
        val result = StringBuilder().apply{
            append("Start eating fruits.\n")
            for (fruit in list){
                append(fruit).append("\n")
            }

            append("Ate all fruits.")
        }

        println(result.toString())
  • with,作用和run一样。不同的是,run由对象点出,而with是独立的函数,对象是作为with的参数。
        val list = listOf("apple", "orange", "pear")
        val result = with(StringBuilder()) {
            append("Start eating fruits.\n")
            for (fruit in list){
                append(fruit).append("\n")
            }

            append("Ate all fruits.")

            toString()
        }

        println(result)

  • let, 把原始对象作为lamda表达式的参数,传入函数体。通常用来简化判空操作, 而且是线程安全的。
object.let{
   it.todo()//在函数体内使用it替代object对象去访问其公有的属性和方法
   ...
}

//另一种用途 判断object为null的操作
object?.let{//表示object不为null的条件下,才会去执行let函数体
   it.todo()
}

 下面的写法,有点罗嗦,如果使用user的参数方法更多,就要被问号烦死了。

    fun doStudy(user:User?){
        user?.age = 20
        user?.name = "alan"
    }

或者用if判空:

    fun doStudy(user:User?){
        if(user != null){
           user.age = 20
           user.name = "alan"
        }
    }

用let函数简化:

    fun doStudy(user:User?){
        user?.let{
        it.age = 20
        it.name = "alan"
    }

针对if判空那种方式,是有问题的。当User对象是全局对象的时候。就编译错误了。提示有多线程问题。

   var user:User? = null
    fun doStudy() {
        if (user!=null) {
            user.age = 20 //编译错误提醒
            user.name = "alan"//编译错误提醒
        }
    }
  • also, 和let的作用一样。不同点就是,let函数的返回值是最后一行的返回值,而also函数的返回值是返回上下文对象本身。可以理解为"并且为该对象执行以下操作"。

一般可用于多个扩展函数链式调用。

fun main() {
    val user = User("alan", 18)
    val alsoResult = user.also {
        println("user 之前的名字是:${it.name}") //user 之前的名字是:alan
    }.apply {
        name = "lin"
    }
    println(alsoResult) //User(name=lin, age=18)
    println(user) //User(name=lin, age=18)
    println(alsoResult === user) //true
}

data class User(var name: String, var age: Int)
  • takeIf,takeunless, 前面调用了一个函数计算得出了一个结果,现在需要对这个结果做一个分支判断,并且我们只需要用到if的一个分支时,可以用takeIf和takeUnless代替。

takeIf,takeunless, 区别就只有一个是满足代码块里面的条件才返回对象本身,一个是不满足条件才返回。

下面三段代码都是等价的:

用if语句:

    fun testWithoutTakeIf() {
        val name = "alan Gong"
        val hasGong = name.indexOf("Gong")
        Log.i(TAG, "testWithoutTakeIf: hasGong = $hasGong")
        if (hasGong >= 0) {
            Log.i(TAG, "testWithoutTakeIf: has Gong")
        }
        Log.i(TAG, "testWithoutTakeIf: $name")
    }
    
输出:
I: testWithoutTakeIf: hasGong = 0
I: testWithoutTakeIf: has Gong 
I: testWithoutTakeIf: alan Gong

用takeIf:

    fun testTakeIf() {
        val name = "alan Gong"
        name.indexOf("Gong")
            .takeIf {
                Log.i(TAG, "testTakeIf: it = $it")
                it >= 0
            }
            ?.let {
                Log.i(TAG, "testTakeIf: has Gong")
            }
        Log.i(TAG, "testTakeIf: $name")
    }
   
输出:
I: testTakeIf: it = 0
I: testTakeIf: has Gong
I: testTakeIf: alan Gong

用takeLess: 注意函数体的判断和takeIf函数体里相反。

    fun testTakeUnless() {
        val name = "alan Gong"
        name.indexOf("Gong")
            .takeUnless {
                Log.i(TAG, "testTakeUnless: it = $it")
                it < 0
            }
            ?.let {
                Log.i(TAG, "testTakeUnless: has Gong")
            }
        Log.i(TAG, "testTakeUnless: $name")
    }
    
输出:
I: testTakeUnless: it = 0
I: testTakeUnless: has  Gong
I: testTakeUnless: alan Gong

由上面的简单例子也可以看出,这两个通常和其他作用域函数,组成链式调用。

  • repeat, 循环执行n次block中的代码。
repeat(3){
    println("repeat")
}

好了,目前所有的作用域函数都记录清楚了。看起来是挺强大的,但是这种东西多了,可读性就不见得好了。另外还有一张网络上的总结图:

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值