如何使用Kotlin Scope 方法及takeIf/takeUnless

如何使用Kotlin Scope 方法及takeIf/takeUnless


StardardKt类提供以下几个常用的方法

5个scope方法 +2个方法

  • let
  • run
  • apply
  • also
  • with
  • takeIf/takeUnless ( StardardKt)
什么是 scope functions?

The Kotlin standard library contains several functions whose sole purpose is to execute a block of code within the context of an object. When you call such a function on an object with a lambda expression provided, it forms a temporary scope. In this scope, you can access the object without its name. Such functions are called scope functions.

简单理解,在上下文对象范围 (大括号) 内,可以不用对象的名字,直接调用

scope方法的区别
  • 上下文对象引用方式(this or it)
  • 返回值 (上下文对象 或者 lambda结果)
let示例 (上下文对象it, 返回值lambda的结果)
Person("Alice", 20, "Amsterdam").let {
	println(it)
	it.moveTo("London")
	it.incrementAge()
	println(it) // 这里是Unit
}

正常写

val alice = Person("Alice", 20, "Amsterdam")
println(alice)
alice.moveTo("London")
alice.incrementAge()
println(alice)

The scope functions do not introduce any new technical capabilities, but they can make your code,more concise and readable.

scope functions 使得代码更加简洁易读

apply示例 (上下文对象this,可省略, 返回上下文对象)
val adam = Person("Adam").apply {
	age = 20 // same as this.age = 20 or adam.age = 20
	city = "London"
}
println(adam)

这是不是比设计模式中builder模式更加简单,创建对象更加简洁

also示例 (上下文对象it, 返回上下文对象)
fun getRandomInt(): Int {
	return Random.nextInt(100).also {
		writeToLog("getRandomInt() generated value $it")
	}
}
val i = getRandomInt()

做额外操作,如日志,埋点

run示例 (上下文对象this,可省略, 返回lambda结果)
val numbers = mutableListOf("one", "two", "three")
val countEndsWithE = numbers.run {
	add("four")
	add("five")
	count { it.endsWith("e") } //返回count计数的结果
}
println("There are $countEndsWithE elements that end with e.")

run is useful when your lambda contains both the object initialization and the computation of the return value.

同时进行对象初始化和返回计算结果时推荐使用

kotlin.run示例 (无上下文, 返回值是lambda的记过)
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)
}

将相同功能代码聚在一起

with示例 (上下文对象this,可省略, 返回lambda 结果)
val numbers = mutableListOf("one", "two", "three")
with(numbers) {
	println("'with' is called with argument $this")
	println("It contains $size elements")
}

官网建议不要返回lambda 结果,即返回Unit

run 与 let对比 (上下文对象不同)
val service = MultiportService("https://example.kotlinlang.org", 80)
val result = service.run {
	port = 8080
	query(prepareRequest() + " to port $port")
}
// the same code written with let() function:
val letResult = service.let {
	it.port = 8080
	it.query(it.prepareRequest() + " to port ${it.port}")
}

🌟scope 方法的选择🌟

官网的不同方法差异

方法引用对象返回值是否扩展函数
letitLambda 结果Yes
runthisLambda 结果Yes
kotlin.run-Lambda 结果No: 调用不需要上下文对象
withthisLambda 结果No: 上下文对象作为参数
applythis上下文对象Yes
alsoit上下文对象Yes

简化成下图

选择

简单调用总结

  • let
    • 非空对象执行lambda
    • lambda表示作为变量
  • apply
    • 对象初始化
  • run
    • 对象初始化并计算结果
  • kotlin.run
    • 表达式语句
  • also
    • 附加操作
  • with
    • Grouping function calls on an object (分组方法调用? 比较少用,不是很清楚,一般都用run代替)

⚠️注意

  • 虽然scope 方法使得代码更加简洁,但不要过度使用,这样会使代码可读性降低,甚至会导致错误
  • 避免嵌套使用,如果嵌套请注意上下文对象是this 还是 it
  • ⚠️外部有相同名字的变量时, run ,apply中this不能省略,否者会使用外部的变量
null check
//都用过?.let
obj?.let{

}
//其实?.run 也行,省略上下文,但是注意不要跟局部或者成员变量的属性搞混了
obj?.run{

}

其实可以混用,但是为了可读性,限制使用场景

takeIf and takeUnless

这两的扩展也是stardartKt里的,官方kotlon-docs也放在scope funciton 里介绍的存在的目的就是更好的进行链式调用 (checks of the object state in call chains)

val number = Random.nextInt(100)
val evenOrNull = number.takeIf { it % 2 == 0 }
val oddOrNull = number.takeUnless { it % 2 == 0 }
println("even: $evenOrNull, odd: $oddOrNull")

一般是由都是搭配elvis表示式使用

//变量
val showName = name.takeIf{ it.isNullOrEmpty()} ?: "default" 

//代码块 , 可以取代 if else , 一链到底是不是很爽
name.takeIf{ it.isNullOrEmpty()}
	?.let {
			//满足条件时执行
		  } ?:kotlin.run {
		     //不满足条件时执行
		  }

以上是个人的使用经验,如有问题或者更好的,欢迎留言.

参考

Using Scoped Functions in Kotlin - let, run, with, also, apply

kotlin-docs scope-functions

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值