在不详尽的情况下使用 Kotlin 的作用域函数 with / when

Using Kotlin's scope functions in not exhaustive with / when

我是 Kotlin 的新手,我正在尝试了解 Kotlin 的 scope functions

我的代码如下所示:

with(something) {
 when {
   equals("test") -> var1 = "test123"
   startsWith("test2") -> var2 = "test456"
   contains("test3") -> myNullableVar?.let { it.var3 = "test789" }
  }
}

因此,在我使用 .let 函数进行第三次检查之前,我的 with 函数不需要详尽无遗(我不是 returning 某些东西,我只是做作业)。在我的第三次检查中,我使用 .let 作为空检查...但仅用于 it.var3 的分配(如果它不是 null)。我不需要 return 任何东西,而我知道 Kotlin 的 .let 函数 return 是主体的标准结果。

尽管如此,现在我的 with/when 需要详尽无遗,否则它将无法再编译。

这让我开始思考和尝试不同的事情。我找到了这些方法来解决这个问题:

  1. 我可以在我的 with/when 中添加一个 else,这样它就变得详尽无遗,但实际上我不需要 else,我不想在这种情况下使用它。
  2. 我可以添加另一个 .let,所以它看起来像这样:myNullableVar?.let { it.var3 = "test789" }.let{} ....但这对我来说有点老套。它应该像这样工作吗?
  3. 使用 If(xy==null){...}else{...} 东西,但我想我可以用 Kotlin 以不同的方式解决这个问题

因为我是 Kotlin 的新手,所以我不太确定如何正确处理这种情况。我可能会接受我的第二个想法,因为“它有效”。还是我不应该使用 .let 进行空值检查?再加一个空的.let{}?还是我根本没有理解空安全概念?我觉得这里有点失落。感谢您的帮助。

这似乎是一个不幸的功能组合……

A when 只有当它不是 return 值时才可以是 non-exhaustive。问题是 with() 函数 return 一个值。由于 when 在底部,它的值是 returned 的值,所以在这种情况下它必须是详尽无遗的。

那么,为什么它不坚持 else 分支,即使您省略了“test3”分支?那是因为赋值不会产生值。 (它们的计算结果为 Unit,这是 Kotlin 对没有 return 有用值的函数的特殊类型。)如果每个分支都给出 Unit,那么 Kotlin 似乎 * 很高兴推断出默认分支也给出了 Unit.

但是“test3”分支 return 是其他东西 — myNullableVar 的类型。那么 when 推断出什么类型呢?该类型和 Unit 最接近的公共超类型,即顶级类型 Any?现在 它需要一个明确的 else 分支!

那怎么办?

您找到了几个选项,none 其中最理想的。所以这里还有一些,同上!

  • 您可以 return 来自该分支的显式 Unit

      contains("test3") -> { myNullableVar?.let { it.var3 = "test789" }; Unit }
    
  • 您可以 return 来自 with() 的显式 Unit:

              contains("test3") -> myNullableVar?.let { it.var3 = "test789" }
          }
          Unit
      }
    
  • 您可以为 with() 指定一个明确的类型。 (它有 两个 类型参数,因此您需要同时提供这两个参数,从其参数的类型开始):

      with<String, Unit>("abc") {
    

恐怕我还没有找到一个明显的最佳答案……

然后回答你的最后一个问题:是的,?.let{ 是完全惯用的,并且对于空值检查很常见。在这种特殊情况下,将其替换为 if 恰好解决了类型问题:

contains("test3") -> { if (myNullableVar != null) myNullableVar.var3 = "test789" }

但是除了 long-winded,如果 myNullableVar 是一个 属性 而不是局部变量,那么它会打开一个竞争条件(如果另一个线程将它设置为null 在测试和赋值之间?)所以编译器会抱怨——这正是人们使用 let 的原因!


(*我找不到此行为的参考资料。有官方说法吗?)