Kotlin:在“ null”作弊时如何使用其他条件让let块使用

Arp*_*ogi 3 null kotlin

我在代码中用let块替换了所有空检查,

1.带空检查的代码示例:

if(someValue != null){//run if someValue is not null}
else {//run if someValue is null}
Run Code Online (Sandbox Code Playgroud)

2.如果进行空检查,则使用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
}
Run Code Online (Sandbox Code Playgroud)

现在,让运行块的问题在于,即使someValue不为null,两个代码块也在运行。因此,我无法将代码示例1中if-else条件的行为复制到代码示例2中的run-let条件。

预期的行为是根据value为null或not null来执行let或run代码块。

Arp*_*ogi 11

来源 - kotlinlang.org

  • ?. 执行安全调用(如果接收者为非空,则调用方法或访问属性)
  • ?: 如果左侧值为空,则采用右侧值(elvis 运算符)

改变?。with ?:将解决这个问题,

代码库如下,将根据空检查运行 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 will run only when if someValue is null, like else condition
}
Run Code Online (Sandbox Code Playgroud)

  • 我认为,正如其他答案中提到的,使用 ?.also 而不是 ?.let 很重要,因为 ?.let 与原始代码不同(正如其他答案中指出的那样)... (2认同)

Fra*_*esc 7

您可以创建一个扩展函数,如下所示

fun <T> T?.whenNull(block: () -> Unit) = this ?: block()
Run Code Online (Sandbox Code Playgroud)

然后你就这样称呼它

somevalue?.let { safeSomeValue ->
    // TODO
}.whenNull {
    // execute when someValue is null
}
Run Code Online (Sandbox Code Playgroud)


zsm*_*b13 6

I am replacing all the null check with let block in my code

The first question here is, why? Is this somehow more readable for you than the regular if-else structure? I'd be generally wary of refactoring just for refactoring's sake.

The second consideration is much more important: this conversion you're doing is not equivalent to the original code, you're actually modifying the behavior with this change. Take the following piece of code:

var someValue : String? = null
someValue = "SOF"

someValue?.let {safeSomeValue->
    foo(someSafeValue)
    bar(someSafeValue)
} ?: run {
    println("shouldn't happen if someValue != null")
}
Run Code Online (Sandbox Code Playgroud)

You expect the run block to execute only if someValue == null, but that's actually not the only case when it will run. The entire someValue?.let { ... } expression can produce null values not just when someValue itself was null, but also if the block passed to let returned null. In this case, if the bar() function call results in null, the run statement will be executed afterwards, therefore running both branches of what you thought was a fancied up if-else statement.

  • +1:不要仅仅因为它是新奇的或者有人告诉您它对语言更惯用,就将您的代码从经过长期测试的可靠解决方案中重构出来。如果您无法给出更改的具体原因,请不要修复未解决的问题。 (2认同)

Ale*_*nov 6

举一个非常具体的例子来说明 zsmb13 的回答所谈论的内容:

val someValue = 0
someValue?.let { safeSomeValue->
    println("then")
    null
} ?: run {
    println("else")
}
Run Code Online (Sandbox Code Playgroud)

打印thenelse。您可以使用also代替解决此问题let

val someValue = 0
someValue?.also { safeSomeValue->
    println("then")
    null
} ?: run {
    println("else")
}
Run Code Online (Sandbox Code Playgroud)

只会打印then. 阅读https://kotlinlang.org/docs/reference/scope-functions.html并找出原因并证明它确实总是与原始if ... else. 但我也同意 zsmb13 这可能是一个坏主意。