作为代码审查过程的一部分,我将代码中的所有空检查替换为 let 块。
1.具有空检查的代码示例:
if(someValue != null){//run if someValue is not null}
else {//run if someValue is null}
阿拉伯数字。使用 let-run 块后的代码库,如果用于空检查,
var someValue : String? = null
someValue = "SOF"
someValue?.let {safeSomeValue->
//This code block will run only if someValue is not null
}?.run {
//This code block should run only when if someValue is null, like else condition
}
现在 let-run 块的问题是,即使 someValue 不为 null,两个代码块也在运行。所以我无法将代码示例 1 中的 if-else 条件的行为复制到代码示例 2 中的 run-let 条件。
预期的行为是根据值是否为 null 或非 null 来执行 let 或运行代码块。
来源 - kotlinlang.org
- 执行安全调用(如果接收方为非 null,则调用方法或访问属性(
- ?:如果左侧值为 null,则取右侧值(猫王运算符(
更改 ?. 与 ?:将解决此问题,
代码库如下,将根据空检查运行 let 或运行块。
var someValue : String? = null
someValue = "SOF"
someValue?.also {safeSomeValue->
//This code block will run only if someValue is not null
}?:run {
//This code block will run only if someValue is null, like else condition
}
我正在用代码中的 let 块替换所有空检查
这里的第一个问题是,为什么?这对您来说是否比常规if-else
结构更具可读性?我通常会对仅仅为了重构而重构持谨慎态度。
第二个考虑因素更为重要:您正在执行的转换并不等同于原始代码,您实际上是在通过此更改修改行为。采用以下代码段:
var someValue : String? = null
someValue = "SOF"
someValue?.let {safeSomeValue->
foo(someSafeValue)
bar(someSafeValue)
} ?: run {
println("shouldn't happen if someValue != null")
}
您希望run
块仅在someValue == null
时执行,但这实际上并不是它运行的唯一情况。整个someValue?.let { ... }
表达式不仅可以在someValue
本身被null
时产生null
值,而且如果块传递给let
返回null
。在这种情况下,如果bar()
函数调用导致null
,则run
语句将在之后执行,因此运行您认为是幻想的if-else
语句的两个分支。
举一个非常具体的例子来说明 zsmb13 的答案所谈论的内容:
val someValue = 0
someValue?.let { safeSomeValue->
println("then")
null
} ?: run {
println("else")
}
打印then
和else
。您可以通过使用 also
而不是 let
来解决此问题:
val someValue = 0
someValue?.also { safeSomeValue->
println("then")
null
} ?: run {
println("else")
}
只会打印then
.阅读 https://kotlinlang.org/docs/reference/scope-functions.html 并找出原因并证明它确实总是等同于原始if ... else
可能会很有用。但我也同意 zsmb13 的观点,这可能是一个坏主意。
你可以创建一个扩展函数,像这样
fun <T> T?.whenNull(block: () -> Unit) = this ?: block()
然后你这样称呼它
somevalue?.let { safeSomeValue ->
// TODO
}.whenNull {
// execute when someValue is null
}
有时你会发现以下有用的
inline fun <T> T?.itOrNull(
ifValue: (T) -> Unit,
ifNull: () -> Unit
): Unit = when (this) {
null -> ifNull()
else -> ifValue(this)
}
用法:
data.title?.itOrNull(
{ view.text = it },
{ view.visibility = View.GONE }
)
您可以编写两个扩展函数,例如:"ifSafe"和"ifNull",它们可以单独使用或链接在一起以模仿 if/else 模式:
fun <T> T?.ifSafe(block: (t:T?) -> Unit) = if (this!=null) block(this) else this
fun Any?.ifNull(block: () -> Unit?) = if (this==null) block().also{return null} else this
fun main() {
var someValue = 4
var nullValue = null
someValue.ifSafe { safeSomeValue ->
println("someValue: "+safeSomeValue.toString())
null
}.ifNull{
println("someValue is null.")
}
someValue.ifNull{
println("someValue is null.")
}.ifSafe{ safeSomeValue ->
println(safeSomeValue)
}
nullValue.ifNull{
println("nullValue is null.")
}
}