本篇文章主要分享一下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}")
今天是周末,各位读者周末愉快。
觉得文章不错的,给我点个赞哇,关注一下呗!
技术交流可关注公众号【君伟说】,加我好友一起探讨