说说kotlin中的作用域函数

本篇文章主要分享一下Kotlin的作用域函数let, run, with, apply和also的用法及区别。

作用域函数在执行过程中,通过lambda 表达式,形成一种临时性的作用域,可以减少部分逻辑代码的数量。

上下文对象:this or it

this

run、with 以及 apply 通过关键字 this 引用上下文对象。因此,在它们的 lambda 表达式中可以像在普通的类函数中一样访问上下文对象。

it

let 及 also 将上下文对象作为 lambda 表达式参数。如果没有指定参数名,对象可以用隐式默认名称 it 访问。it 比 this 简短,带有 it 的表达式通常更容易阅读。

返回值

  • apply 及 also 返回上下文对象。
  • let、run 及 with 返回 lambda 表达式结果.

let函数

let函数在日常开发中经常用到,一般用于非空判断以用于后序的操作使用?.,上下文对象{it} 作为lambda表达的参数,表示lambda的返回值。

data class User(var name: String)
fun main() {
    val user = User("Wangwei")
    //let 和run都会返回闭包的执行结果,区别在于let有闭包参数, 而run没有闭包参数
    val letResult: String = user.let { user: User -> "let::${user.javaClass}" }
    // let中只有一个参数时,闭包参数可以省略,可以用it代替
    val letResults: String = user.let { "let::${it.javaClass}" }
    println(letResult)
    
    var str :String? = "hello"
    // 如果str的值为null, 则let中的函数不会执行
    str?.let {
        println(it.length)
    }
    
    // 用于链式调用结果
    val numbers = mutableListOf<String>("one","two","three","four","five")
    numbers.map { it.length }.filter { it > 3 }.let {
        println(it)
    }
}

with函数

是一个非扩展函数,调用同一个对象的多个方法或属性, 省去对象名重复,直接调用方法名和属性, 上下文对象为 this

val numbers = mutableListOf<String>("one","two","three","four","five")   

with(numbers) {
    println("with argument is $this")
    println("it contain $size element")
    //println("it contain ${this.size} element") 和上面一行效果一致
}

run函数

上下文对象是this, 返回lambda对象,结合了let,with的作用,调用同一对象的多个方法和属性, 省去对象名重复调用, 直接调用属性和方法名,统一做判空处理。

numbers.run {
        println("with argument is $this")
        println("it contain $size element")
    }

    var str1 :String? = "hello"
    str1?.run { 
        println("str1 length is $length")
        println("char is ${get(1)}")
    }

apply函数

上下文对象是 this, 返回值是对象本身,可以在对象上连续链式调用。主要用于对象初始化时进行属性赋值。

data class Person(var name: String, var age: Int = 0, var city: String = ""){}
var testUser = Person("小明").apply {
        age = 18
        city = "上海"
    }
    println(testUser)

also函数

上下文对象 作为lambda表达式参数{it} 使用, 和let参数比较相似

val numbers = mutableListOf<String>("one","two","three","four","five")

numbers.also {
    println("with argument is $it")
    println("it contain ${it.size} element")
}.add("哈哈")

作用域函数如何选择

  • 对一个非空(non-null)对象执行 lambda 表达式:let
  • 将表达式作为变量引入为局部作用域中:let
  • 对象配置:apply
  • 对象配置并且计算结果:run
  • 在需要表达式的地方运行语句:非扩展的 run
  • 附加效果:also
  • 一个对象的一组函数调用:with

takeIf与taceUnless

进行对象检测过滤,开发中常与上述的作用域函数结合使用。

//takeIf的闭包返回一个判断结果, 为false时,takeIf函数返回空
//takeUnless 与 takeIf 刚好相反, 闭包的判断结果,为true时函数会返回空
user.takeIf { it.name.length > 0 }?.also { println("姓名为${it.name}") } ?: println("姓名为空")
user.takeUnless { it.name.length > 0 }?.also { println("姓名为空") } ?: println("姓名为${user.name}")

今天是周末,各位读者周末愉快。

--- End ---


本文分享自微信公众号 - 君伟说(wayne90214)。
如有侵权,请联系 [email protected] 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章